brintos

brintos / linux-shallow public Read only

0
0
Text · 24.7 KiB · f623c25 Raw
897 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * budget.ko: driver for the SAA7146 based Budget DVB cards4 *            without analog video input or CI5 *6 * Compiled from various sources by Michael Hunold <michael@mihu.de>7 *8 * Copyright (C) 2002 Ralph Metzler <rjkm@metzlerbros.de>9 *10 * Copyright (C) 1999-2002 Ralph  Metzler11 *                       & Marcus Metzler for convergence integrated media GmbH12 *13 * 26feb2004 Support for FS Activy Card (Grundig tuner) by14 *           Michael Dreher <michael@5dot1.de>,15 *           Oliver Endriss <o.endriss@gmx.de> and16 *           Andreas 'randy' Weinberger17 *18 * the project's page is at https://linuxtv.org19 */20 21#include "budget.h"22#include "stv0299.h"23#include "ves1x93.h"24#include "ves1820.h"25#include "l64781.h"26#include "tda8083.h"27#include "s5h1420.h"28#include "tda10086.h"29#include "tda826x.h"30#include "lnbp21.h"31#include "bsru6.h"32#include "bsbe1.h"33#include "tdhd1.h"34#include "stv6110x.h"35#include "stv090x.h"36#include "isl6423.h"37#include "lnbh24.h"38 39 40static int diseqc_method;41module_param(diseqc_method, int, 0444);42MODULE_PARM_DESC(diseqc_method, "Select DiSEqC method for subsystem id 13c2:1003, 0: default, 1: more reliable (for newer revisions only)");43 44DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);45 46static void Set22K(struct budget *budget, int state)47{48	struct saa7146_dev *dev = budget->dev;49 50	dprintk(2, "budget: %p\n", budget);51	saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO));52}53 54/*55 * Diseqc functions only for TT Budget card56 * taken from the Skyvision DVB driver by57 * Ralph Metzler <rjkm@metzlerbros.de>58 */59 60static void DiseqcSendBit(struct budget *budget, int data)61{62	struct saa7146_dev *dev = budget->dev;63 64	dprintk(2, "budget: %p\n", budget);65 66	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);67	udelay(data ? 500 : 1000);68	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);69	udelay(data ? 1000 : 500);70}71 72static void DiseqcSendByte(struct budget *budget, int data)73{74	int i, par = 1, d;75 76	dprintk(2, "budget: %p\n", budget);77 78	for (i = 7; i >= 0; i--) {79		d = (data>>i)&1;80		par ^= d;81		DiseqcSendBit(budget, d);82	}83 84	DiseqcSendBit(budget, par);85}86 87static int SendDiSEqCMsg(struct budget *budget, int len, u8 *msg, unsigned long burst)88{89	struct saa7146_dev *dev = budget->dev;90	int i;91 92	dprintk(2, "budget: %p\n", budget);93 94	saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);95	mdelay(16);96 97	for (i = 0; i < len; i++)98		DiseqcSendByte(budget, msg[i]);99 100	mdelay(16);101 102	if (burst != -1) {103		if (burst) {104			DiseqcSendByte(budget, 0xff);105		} else {106			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI);107			mdelay(12);108			udelay(500);109			saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO);110		}111		msleep(20);112	}113 114	return 0;115}116 117/*118 *   Routines for the Fujitsu Siemens Activy budget card119 *   22 kHz tone and DiSEqC are handled by the frontend.120 *   Voltage must be set here.121 *   GPIO 1: LNBP EN, GPIO 2: LNBP VSEL122 */123static int SetVoltage_Activy(struct budget *budget,124			     enum fe_sec_voltage voltage)125{126	struct saa7146_dev *dev = budget->dev;127 128	dprintk(2, "budget: %p\n", budget);129 130	switch (voltage) {131	case SEC_VOLTAGE_13:132		saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);133		saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTLO);134		break;135	case SEC_VOLTAGE_18:136		saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTHI);137		saa7146_setgpio(dev, 2, SAA7146_GPIO_OUTHI);138		break;139	case SEC_VOLTAGE_OFF:140		saa7146_setgpio(dev, 1, SAA7146_GPIO_OUTLO);141		break;142	default:143		return -EINVAL;144	}145 146	return 0;147}148 149static int siemens_budget_set_voltage(struct dvb_frontend *fe,150				      enum fe_sec_voltage voltage)151{152	struct budget *budget = fe->dvb->priv;153 154	return SetVoltage_Activy(budget, voltage);155}156 157static int budget_set_tone(struct dvb_frontend *fe,158			   enum fe_sec_tone_mode tone)159{160	struct budget *budget = fe->dvb->priv;161 162	switch (tone) {163	case SEC_TONE_ON:164		Set22K(budget, 1);165		break;166 167	case SEC_TONE_OFF:168		Set22K(budget, 0);169		break;170 171	default:172		return -EINVAL;173	}174 175	return 0;176}177 178static int budget_diseqc_send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd)179{180	struct budget *budget = fe->dvb->priv;181 182	SendDiSEqCMsg(budget, cmd->msg_len, cmd->msg, 0);183 184	return 0;185}186 187static int budget_diseqc_send_burst(struct dvb_frontend *fe,188				    enum fe_sec_mini_cmd minicmd)189{190	struct budget *budget = fe->dvb->priv;191 192	SendDiSEqCMsg(budget, 0, NULL, minicmd);193 194	return 0;195}196 197static int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe)198{199	struct dtv_frontend_properties *c = &fe->dtv_property_cache;200	struct budget *budget = fe->dvb->priv;201	u8 pwr = 0;202	u8 buf[4];203	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) };204	u32 div = (c->frequency + 479500) / 125;205 206	if (c->frequency > 2000000)207		pwr = 3;208	else if (c->frequency > 1800000)209		pwr = 2;210	else if (c->frequency > 1600000)211		pwr = 1;212	else if (c->frequency > 1200000)213		pwr = 0;214	else if (c->frequency >= 1100000)215		pwr = 1;216	else217		pwr = 2;218 219	buf[0] = (div >> 8) & 0x7f;220	buf[1] = div & 0xff;221	buf[2] = ((div & 0x18000) >> 10) | 0x95;222	buf[3] = (pwr << 6) | 0x30;223 224	// NOTE: since we're using a prescaler of 2, we set the225	// divisor frequency to 62.5kHz and divide by 125 above226 227	if (fe->ops.i2c_gate_ctrl)228		fe->ops.i2c_gate_ctrl(fe, 1);229	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)230		return -EIO;231	return 0;232}233 234static struct ves1x93_config alps_bsrv2_config = {235	.demod_address = 0x08,236	.xin = 90100000UL,237	.invert_pwm = 0,238};239 240static int alps_tdbe2_tuner_set_params(struct dvb_frontend *fe)241{242	struct dtv_frontend_properties *c = &fe->dtv_property_cache;243	struct budget *budget = fe->dvb->priv;244	u32 div;245	u8 data[4];246	struct i2c_msg msg = { .addr = 0x62, .flags = 0, .buf = data, .len = sizeof(data) };247 248	div = (c->frequency + 35937500 + 31250) / 62500;249 250	data[0] = (div >> 8) & 0x7f;251	data[1] = div & 0xff;252	data[2] = 0x85 | ((div >> 10) & 0x60);253	data[3] = (c->frequency < 174000000 ? 0x88 : c->frequency < 470000000 ? 0x84 : 0x81);254 255	if (fe->ops.i2c_gate_ctrl)256		fe->ops.i2c_gate_ctrl(fe, 1);257	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)258		return -EIO;259	return 0;260}261 262static struct ves1820_config alps_tdbe2_config = {263	.demod_address = 0x09,264	.xin = 57840000UL,265	.invert = 1,266	.selagc = VES1820_SELAGC_SIGNAMPERR,267};268 269static int grundig_29504_401_tuner_set_params(struct dvb_frontend *fe)270{271	struct dtv_frontend_properties *c = &fe->dtv_property_cache;272	struct budget *budget = fe->dvb->priv;273	u8 *tuner_addr = fe->tuner_priv;274	u32 div;275	u8 cfg, cpump, band_select;276	u8 data[4];277	struct i2c_msg msg = { .flags = 0, .buf = data, .len = sizeof(data) };278 279	if (tuner_addr)280		msg.addr = *tuner_addr;281	else282		msg.addr = 0x61;283 284	div = (36125000 + c->frequency) / 166666;285 286	cfg = 0x88;287 288	if (c->frequency < 175000000)289		cpump = 2;290	else if (c->frequency < 390000000)291		cpump = 1;292	else if (c->frequency < 470000000)293		cpump = 2;294	else if (c->frequency < 750000000)295		cpump = 1;296	else297		cpump = 3;298 299	if (c->frequency < 175000000)300		band_select = 0x0e;301	else if (c->frequency < 470000000)302		band_select = 0x05;303	else304		band_select = 0x03;305 306	data[0] = (div >> 8) & 0x7f;307	data[1] = div & 0xff;308	data[2] = ((div >> 10) & 0x60) | cfg;309	data[3] = (cpump << 6) | band_select;310 311	if (fe->ops.i2c_gate_ctrl)312		fe->ops.i2c_gate_ctrl(fe, 1);313	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)314		return -EIO;315	return 0;316}317 318static struct l64781_config grundig_29504_401_config = {319	.demod_address = 0x55,320};321 322static struct l64781_config grundig_29504_401_config_activy = {323	.demod_address = 0x54,324};325 326static u8 tuner_address_grundig_29504_401_activy = 0x60;327 328static int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe)329{330	struct dtv_frontend_properties *c = &fe->dtv_property_cache;331	struct budget *budget = fe->dvb->priv;332	u32 div;333	u8 data[4];334	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };335 336	div = c->frequency / 125;337	data[0] = (div >> 8) & 0x7f;338	data[1] = div & 0xff;339	data[2] = 0x8e;340	data[3] = 0x00;341 342	if (fe->ops.i2c_gate_ctrl)343		fe->ops.i2c_gate_ctrl(fe, 1);344	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)345		return -EIO;346	return 0;347}348 349static struct tda8083_config grundig_29504_451_config = {350	.demod_address = 0x68,351};352 353static int s5h1420_tuner_set_params(struct dvb_frontend *fe)354{355	struct dtv_frontend_properties *c = &fe->dtv_property_cache;356	struct budget *budget = fe->dvb->priv;357	u32 div;358	u8 data[4];359	struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) };360 361	div = c->frequency / 1000;362	data[0] = (div >> 8) & 0x7f;363	data[1] = div & 0xff;364	data[2] = 0xc2;365 366	if (div < 1450)367		data[3] = 0x00;368	else if (div < 1850)369		data[3] = 0x40;370	else if (div < 2000)371		data[3] = 0x80;372	else373		data[3] = 0xc0;374 375	if (fe->ops.i2c_gate_ctrl)376		fe->ops.i2c_gate_ctrl(fe, 1);377	if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1)378		return -EIO;379 380	return 0;381}382 383static struct s5h1420_config s5h1420_config = {384	.demod_address = 0x53,385	.invert = 1,386	.cdclk_polarity = 1,387};388 389static struct tda10086_config tda10086_config = {390	.demod_address = 0x0e,391	.invert = 0,392	.diseqc_tone = 1,393	.xtal_freq = TDA10086_XTAL_16M,394};395 396static const struct stv0299_config alps_bsru6_config_activy = {397	.demod_address = 0x68,398	.inittab = alps_bsru6_inittab,399	.mclk = 88000000UL,400	.invert = 1,401	.op0_off = 1,402	.min_delay_ms = 100,403	.set_symbol_rate = alps_bsru6_set_symbol_rate,404};405 406static const struct stv0299_config alps_bsbe1_config_activy = {407	.demod_address = 0x68,408	.inittab = alps_bsbe1_inittab,409	.mclk = 88000000UL,410	.invert = 1,411	.op0_off = 1,412	.min_delay_ms = 100,413	.set_symbol_rate = alps_bsbe1_set_symbol_rate,414};415 416static int alps_tdhd1_204_request_firmware(struct dvb_frontend *fe, const struct firmware **fw, char *name)417{418	struct budget *budget = fe->dvb->priv;419 420	return request_firmware(fw, name, &budget->dev->pci->dev);421}422 423 424static int i2c_readreg(struct i2c_adapter *i2c, u8 adr, u8 reg)425{426	u8 val;427	struct i2c_msg msg[] = {428		{ .addr = adr, .flags = 0, .buf = &reg, .len = 1 },429		{ .addr = adr, .flags = I2C_M_RD, .buf = &val, .len = 1 }430	};431 432	return (i2c_transfer(i2c, msg, 2) != 2) ? -EIO : val;433}434 435static u8 read_pwm(struct budget *budget)436{437	u8 b = 0xff;438	u8 pwm;439	struct i2c_msg msg[] = { { .addr = 0x50, .flags = 0, .buf = &b, .len = 1 },440				 { .addr = 0x50, .flags = I2C_M_RD, .buf = &pwm, .len = 1} };441 442	if ((i2c_transfer(&budget->i2c_adap, msg, 2) != 2) || (pwm == 0xff))443		pwm = 0x48;444 445	return pwm;446}447 448static struct stv090x_config tt1600_stv090x_config = {449	.device			= STV0903,450	.demod_mode		= STV090x_SINGLE,451	.clk_mode		= STV090x_CLK_EXT,452 453	.xtal			= 13500000,454	.address		= 0x68,455 456	.ts1_mode		= STV090x_TSMODE_DVBCI,457	.ts2_mode		= STV090x_TSMODE_SERIAL_CONTINUOUS,458 459	.repeater_level		= STV090x_RPTLEVEL_16,460 461	.tuner_init		= NULL,462	.tuner_sleep		= NULL,463	.tuner_set_mode		= NULL,464	.tuner_set_frequency	= NULL,465	.tuner_get_frequency	= NULL,466	.tuner_set_bandwidth	= NULL,467	.tuner_get_bandwidth	= NULL,468	.tuner_set_bbgain	= NULL,469	.tuner_get_bbgain	= NULL,470	.tuner_set_refclk	= NULL,471	.tuner_get_status	= NULL,472};473 474static struct stv6110x_config tt1600_stv6110x_config = {475	.addr			= 0x60,476	.refclk			= 27000000,477	.clk_div		= 2,478};479 480static struct isl6423_config tt1600_isl6423_config = {481	.current_max		= SEC_CURRENT_515m,482	.curlim			= SEC_CURRENT_LIM_ON,483	.mod_extern		= 1,484	.addr			= 0x08,485};486 487static void frontend_init(struct budget *budget)488{489	(void)alps_bsbe1_config; /* avoid warning */490 491	switch (budget->dev->pci->subsystem_device) {492	case 0x1003: // Hauppauge/TT Nova budget (stv0299/ALPS BSRU6(tsa5059) OR ves1893/ALPS BSRV2(sp5659))493	case 0x1013:494		// try the ALPS BSRV2 first of all495		budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap);496		if (budget->dvb_frontend) {497			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params;498			budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;499			budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;500			budget->dvb_frontend->ops.set_tone = budget_set_tone;501			break;502		}503 504		// try the ALPS BSRU6 now505		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);506		if (budget->dvb_frontend) {507			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;508			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;509			if (budget->dev->pci->subsystem_device == 0x1003 && diseqc_method == 0) {510				budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd;511				budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst;512				budget->dvb_frontend->ops.set_tone = budget_set_tone;513			}514			break;515		}516		break;517 518	case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659))519 520		budget->dvb_frontend = dvb_attach(ves1820_attach, &alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget));521		if (budget->dvb_frontend) {522			budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params;523			break;524		}525		break;526 527	case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060))528 529		budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config, &budget->i2c_adap);530		if (budget->dvb_frontend) {531			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;532			budget->dvb_frontend->tuner_priv = NULL;533			break;534		}535		break;536 537	case 0x4f52: /* Cards based on Philips Semi Sylt PCI ref. design */538		budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap);539		if (budget->dvb_frontend) {540			pr_info("tuner ALPS BSRU6 in Philips Semi. Sylt detected\n");541			budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;542			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;543			break;544		}545		break;546 547	case 0x4f60: /* Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/tsa5059) */548	{549		int subtype = i2c_readreg(&budget->i2c_adap, 0x50, 0x67);550 551		if (subtype < 0)552			break;553		/* fixme: find a better way to identify the card */554		if (subtype < 0x36) {555			/* assume ALPS BSRU6 */556			budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config_activy, &budget->i2c_adap);557			if (budget->dvb_frontend) {558				pr_info("tuner ALPS BSRU6 detected\n");559				budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params;560				budget->dvb_frontend->tuner_priv = &budget->i2c_adap;561				budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;562				budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;563				break;564			}565		} else {566			/* assume ALPS BSBE1 */567			/* reset tuner */568			saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTLO);569			msleep(50);570			saa7146_setgpio(budget->dev, 3, SAA7146_GPIO_OUTHI);571			msleep(250);572			budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsbe1_config_activy, &budget->i2c_adap);573			if (budget->dvb_frontend) {574				pr_info("tuner ALPS BSBE1 detected\n");575				budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params;576				budget->dvb_frontend->tuner_priv = &budget->i2c_adap;577				budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;578				budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;579				break;580			}581		}582		break;583	}584 585	case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522))586		budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap);587		if (budget->dvb_frontend) {588			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params;589			budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage;590			budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL;591		}592		break;593 594	case 0x5f60: /* Fujitsu Siemens Activy Budget-T PCI rev AL (tda10046/ALPS TDHD1-204A) */595		budget->dvb_frontend = dvb_attach(tda10046_attach, &alps_tdhd1_204a_config, &budget->i2c_adap);596		if (budget->dvb_frontend) {597			budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdhd1_204a_tuner_set_params;598			budget->dvb_frontend->tuner_priv = &budget->i2c_adap;599		}600		break;601 602	case 0x5f61: /* Fujitsu Siemens Activy Budget-T PCI rev GR (L64781/Grundig 29504-401(tsa5060)) */603		budget->dvb_frontend = dvb_attach(l64781_attach, &grundig_29504_401_config_activy, &budget->i2c_adap);604		if (budget->dvb_frontend) {605			budget->dvb_frontend->tuner_priv = &tuner_address_grundig_29504_401_activy;606			budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params;607		}608		break;609 610	case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260))611	{612		struct dvb_frontend *fe;613 614		fe = dvb_attach(s5h1420_attach, &s5h1420_config, &budget->i2c_adap);615		if (fe) {616			fe->ops.tuner_ops.set_params = s5h1420_tuner_set_params;617			budget->dvb_frontend = fe;618			if (dvb_attach(lnbp21_attach, fe, &budget->i2c_adap,619				       0, 0) == NULL) {620				pr_err("%s(): No LNBP21 found!\n", __func__);621				goto error_out;622			}623			break;624		}625	}626		fallthrough;627	case 0x1018: // TT Budget-S-1401 (philips tda10086/philips tda8262)628	{629		struct dvb_frontend *fe;630 631		// gpio2 is connected to CLB - reset it + leave it high632		saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);633		msleep(1);634		saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);635		msleep(1);636 637		fe = dvb_attach(tda10086_attach, &tda10086_config, &budget->i2c_adap);638		if (fe) {639			budget->dvb_frontend = fe;640			if (dvb_attach(tda826x_attach, fe, 0x60,641				       &budget->i2c_adap, 0) == NULL)642				pr_err("%s(): No tda826x found!\n", __func__);643			if (dvb_attach(lnbp21_attach, fe,644				       &budget->i2c_adap, 0, 0) == NULL) {645				pr_err("%s(): No LNBP21 found!\n", __func__);646				goto error_out;647			}648			break;649		}650	}651		fallthrough;652 653	case 0x101c: { /* TT S2-1600 */654			const struct stv6110x_devctl *ctl;655 656			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);657			msleep(50);658			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);659			msleep(250);660 661			budget->dvb_frontend = dvb_attach(stv090x_attach,662							  &tt1600_stv090x_config,663							  &budget->i2c_adap,664							  STV090x_DEMODULATOR_0);665 666			if (budget->dvb_frontend) {667 668				ctl = dvb_attach(stv6110x_attach,669						 budget->dvb_frontend,670						 &tt1600_stv6110x_config,671						 &budget->i2c_adap);672 673				if (ctl) {674					tt1600_stv090x_config.tuner_init	  = ctl->tuner_init;675					tt1600_stv090x_config.tuner_sleep	  = ctl->tuner_sleep;676					tt1600_stv090x_config.tuner_set_mode	  = ctl->tuner_set_mode;677					tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;678					tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;679					tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;680					tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;681					tt1600_stv090x_config.tuner_set_bbgain	  = ctl->tuner_set_bbgain;682					tt1600_stv090x_config.tuner_get_bbgain	  = ctl->tuner_get_bbgain;683					tt1600_stv090x_config.tuner_set_refclk	  = ctl->tuner_set_refclk;684					tt1600_stv090x_config.tuner_get_status	  = ctl->tuner_get_status;685 686					/*687					 * call the init function once to initialize688					 * tuner's clock output divider and demod's689					 * master clock690					 */691					if (budget->dvb_frontend->ops.init)692						budget->dvb_frontend->ops.init(budget->dvb_frontend);693 694					if (dvb_attach(isl6423_attach,695						       budget->dvb_frontend,696						       &budget->i2c_adap,697						       &tt1600_isl6423_config) == NULL) {698						pr_err("%s(): No Intersil ISL6423 found!\n", __func__);699						goto error_out;700					}701				} else {702					pr_err("%s(): No STV6110(A) Silicon Tuner found!\n", __func__);703					goto error_out;704				}705			}706		}707		break;708 709	case 0x1020: { /* Omicom S2 */710			const struct stv6110x_devctl *ctl;711 712			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTLO);713			msleep(50);714			saa7146_setgpio(budget->dev, 2, SAA7146_GPIO_OUTHI);715			msleep(250);716 717			budget->dvb_frontend = dvb_attach(stv090x_attach,718							  &tt1600_stv090x_config,719							  &budget->i2c_adap,720							  STV090x_DEMODULATOR_0);721 722			if (budget->dvb_frontend) {723				pr_info("Omicom S2 detected\n");724 725				ctl = dvb_attach(stv6110x_attach,726						 budget->dvb_frontend,727						 &tt1600_stv6110x_config,728						 &budget->i2c_adap);729 730				if (ctl) {731					tt1600_stv090x_config.tuner_init	  = ctl->tuner_init;732					tt1600_stv090x_config.tuner_sleep	  = ctl->tuner_sleep;733					tt1600_stv090x_config.tuner_set_mode	  = ctl->tuner_set_mode;734					tt1600_stv090x_config.tuner_set_frequency = ctl->tuner_set_frequency;735					tt1600_stv090x_config.tuner_get_frequency = ctl->tuner_get_frequency;736					tt1600_stv090x_config.tuner_set_bandwidth = ctl->tuner_set_bandwidth;737					tt1600_stv090x_config.tuner_get_bandwidth = ctl->tuner_get_bandwidth;738					tt1600_stv090x_config.tuner_set_bbgain	  = ctl->tuner_set_bbgain;739					tt1600_stv090x_config.tuner_get_bbgain	  = ctl->tuner_get_bbgain;740					tt1600_stv090x_config.tuner_set_refclk	  = ctl->tuner_set_refclk;741					tt1600_stv090x_config.tuner_get_status	  = ctl->tuner_get_status;742 743					/*744					 * call the init function once to initialize745					 * tuner's clock output divider and demod's746					 * master clock747					 */748					if (budget->dvb_frontend->ops.init)749						budget->dvb_frontend->ops.init(budget->dvb_frontend);750 751					if (dvb_attach(lnbh24_attach,752							budget->dvb_frontend,753							&budget->i2c_adap,754							LNBH24_PCL | LNBH24_TTX,755							LNBH24_TEN, 0x14>>1) == NULL) {756						pr_err("No LNBH24 found!\n");757						goto error_out;758					}759				} else {760					pr_err("%s(): No STV6110(A) Silicon Tuner found!\n", __func__);761					goto error_out;762				}763			}764		}765		break;766	}767 768	if (budget->dvb_frontend == NULL) {769		pr_err("A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n",770		       budget->dev->pci->vendor,771		       budget->dev->pci->device,772		       budget->dev->pci->subsystem_vendor,773		       budget->dev->pci->subsystem_device);774	} else {775		if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend))776			goto error_out;777	}778	return;779 780error_out:781	pr_err("Frontend registration failed!\n");782	dvb_frontend_detach(budget->dvb_frontend);783	budget->dvb_frontend = NULL;784}785 786static int budget_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_data *info)787{788	struct budget *budget = NULL;789	int err;790 791	budget = kmalloc(sizeof(struct budget), GFP_KERNEL);792	if (budget == NULL)793		return -ENOMEM;794 795	dprintk(2, "dev:%p, info:%p, budget:%p\n", dev, info, budget);796 797	dev->ext_priv = budget;798 799	err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr);800	if (err) {801		pr_err("==> failed\n");802		kfree(budget);803		return err;804	}805 806	budget->dvb_adapter.priv = budget;807	frontend_init(budget);808 809	ttpci_budget_init_hooks(budget);810 811	return 0;812}813 814static int budget_detach(struct saa7146_dev *dev)815{816	struct budget *budget = dev->ext_priv;817	int err;818 819	if (budget->dvb_frontend) {820		dvb_unregister_frontend(budget->dvb_frontend);821		dvb_frontend_detach(budget->dvb_frontend);822	}823 824	err = ttpci_budget_deinit(budget);825 826	kfree(budget);827	dev->ext_priv = NULL;828 829	return err;830}831 832static struct saa7146_extension budget_extension;833 834MAKE_BUDGET_INFO(ttbs,	"TT-Budget/WinTV-NOVA-S  PCI",	BUDGET_TT);835MAKE_BUDGET_INFO(ttbc,	"TT-Budget/WinTV-NOVA-C  PCI",	BUDGET_TT);836MAKE_BUDGET_INFO(ttbt,	"TT-Budget/WinTV-NOVA-T  PCI",	BUDGET_TT);837MAKE_BUDGET_INFO(satel,	"SATELCO Multimedia PCI",	BUDGET_TT_HW_DISEQC);838MAKE_BUDGET_INFO(ttbs1401, "TT-Budget-S-1401 PCI", BUDGET_TT);839MAKE_BUDGET_INFO(tt1600, "TT-Budget S2-1600 PCI", BUDGET_TT);840MAKE_BUDGET_INFO(fsacs0, "Fujitsu Siemens Activy Budget-S PCI (rev GR/grundig frontend)", BUDGET_FS_ACTIVY);841MAKE_BUDGET_INFO(fsacs1, "Fujitsu Siemens Activy Budget-S PCI (rev AL/alps frontend)", BUDGET_FS_ACTIVY);842MAKE_BUDGET_INFO(fsact,	 "Fujitsu Siemens Activy Budget-T PCI (rev GR/Grundig frontend)", BUDGET_FS_ACTIVY);843MAKE_BUDGET_INFO(fsact1, "Fujitsu Siemens Activy Budget-T PCI (rev AL/ALPS TDHD1-204A)", BUDGET_FS_ACTIVY);844MAKE_BUDGET_INFO(omicom, "Omicom S2 PCI", BUDGET_TT);845MAKE_BUDGET_INFO(sylt,   "Philips Semi Sylt PCI", BUDGET_TT_HW_DISEQC);846 847static const struct pci_device_id pci_tbl[] = {848	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1003),849	MAKE_EXTENSION_PCI(ttbc,  0x13c2, 0x1004),850	MAKE_EXTENSION_PCI(ttbt,  0x13c2, 0x1005),851	MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013),852	MAKE_EXTENSION_PCI(ttbs,  0x13c2, 0x1016),853	MAKE_EXTENSION_PCI(ttbs1401, 0x13c2, 0x1018),854	MAKE_EXTENSION_PCI(tt1600, 0x13c2, 0x101c),855	MAKE_EXTENSION_PCI(fsacs1, 0x1131, 0x4f60),856	MAKE_EXTENSION_PCI(fsacs0, 0x1131, 0x4f61),857	MAKE_EXTENSION_PCI(fsact1, 0x1131, 0x5f60),858	MAKE_EXTENSION_PCI(fsact, 0x1131, 0x5f61),859	MAKE_EXTENSION_PCI(omicom, 0x14c4, 0x1020),860	MAKE_EXTENSION_PCI(sylt, 0x1131, 0x4f52),861	{862		.vendor    = 0,863	}864};865 866MODULE_DEVICE_TABLE(pci, pci_tbl);867 868static struct saa7146_extension budget_extension = {869	.name		= "budget dvb",870	.flags		= SAA7146_USE_I2C_IRQ,871 872	.module		= THIS_MODULE,873	.pci_tbl	= pci_tbl,874	.attach		= budget_attach,875	.detach		= budget_detach,876 877	.irq_mask	= MASK_10,878	.irq_func	= ttpci_budget_irq10_handler,879};880 881static int __init budget_init(void)882{883	return saa7146_register_extension(&budget_extension);884}885 886static void __exit budget_exit(void)887{888	saa7146_unregister_extension(&budget_extension);889}890 891module_init(budget_init);892module_exit(budget_exit);893 894MODULE_LICENSE("GPL");895MODULE_AUTHOR("Ralph Metzler, Marcus Metzler, Michael Hunold, others");896MODULE_DESCRIPTION("driver for the SAA7146 based so-called budget PCI DVB cards by Siemens, Technotrend, Hauppauge");897