18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * budget-patch.c: driver for Budget Patch, 48c2ecf20Sopenharmony_ci * hardware modification of DVB-S cards enabling full TS 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * Written by Emard <emard@softhome.net> 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Original idea by Roberto Deza <rdeza@unav.es> 98c2ecf20Sopenharmony_ci * 108c2ecf20Sopenharmony_ci * Special thanks to Holger Waechtler, Michael Hunold, Marian Durkovic 118c2ecf20Sopenharmony_ci * and Metzlerbros 128c2ecf20Sopenharmony_ci * 138c2ecf20Sopenharmony_ci * the project's page is at https://linuxtv.org 148c2ecf20Sopenharmony_ci */ 158c2ecf20Sopenharmony_ci 168c2ecf20Sopenharmony_ci#include "av7110.h" 178c2ecf20Sopenharmony_ci#include "av7110_hw.h" 188c2ecf20Sopenharmony_ci#include "budget.h" 198c2ecf20Sopenharmony_ci#include "stv0299.h" 208c2ecf20Sopenharmony_ci#include "ves1x93.h" 218c2ecf20Sopenharmony_ci#include "tda8083.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#include "bsru6.h" 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_ciDVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci#define budget_patch budget 288c2ecf20Sopenharmony_ci 298c2ecf20Sopenharmony_cistatic struct saa7146_extension budget_extension; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ciMAKE_BUDGET_INFO(ttbp, "TT-Budget/Patch DVB-S 1.x PCI", BUDGET_PATCH); 328c2ecf20Sopenharmony_ci//MAKE_BUDGET_INFO(satel,"TT-Budget/Patch SATELCO PCI", BUDGET_TT_HW_DISEQC); 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_cistatic const struct pci_device_id pci_tbl[] = { 358c2ecf20Sopenharmony_ci MAKE_EXTENSION_PCI(ttbp,0x13c2, 0x0000), 368c2ecf20Sopenharmony_ci// MAKE_EXTENSION_PCI(satel, 0x13c2, 0x1013), 378c2ecf20Sopenharmony_ci { 388c2ecf20Sopenharmony_ci .vendor = 0, 398c2ecf20Sopenharmony_ci } 408c2ecf20Sopenharmony_ci}; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci/* those lines are for budget-patch to be tried 438c2ecf20Sopenharmony_ci** on a true budget card and observe the 448c2ecf20Sopenharmony_ci** behaviour of VSYNC generated by rps1. 458c2ecf20Sopenharmony_ci** this code was shamelessly copy/pasted from budget.c 468c2ecf20Sopenharmony_ci*/ 478c2ecf20Sopenharmony_cistatic void gpio_Set22K (struct budget *budget, int state) 488c2ecf20Sopenharmony_ci{ 498c2ecf20Sopenharmony_ci struct saa7146_dev *dev=budget->dev; 508c2ecf20Sopenharmony_ci dprintk(2, "budget: %p\n", budget); 518c2ecf20Sopenharmony_ci saa7146_setgpio(dev, 3, (state ? SAA7146_GPIO_OUTHI : SAA7146_GPIO_OUTLO)); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* Diseqc functions only for TT Budget card */ 558c2ecf20Sopenharmony_ci/* taken from the Skyvision DVB driver by 568c2ecf20Sopenharmony_ci Ralph Metzler <rjkm@metzlerbros.de> */ 578c2ecf20Sopenharmony_ci 588c2ecf20Sopenharmony_cistatic void DiseqcSendBit (struct budget *budget, int data) 598c2ecf20Sopenharmony_ci{ 608c2ecf20Sopenharmony_ci struct saa7146_dev *dev=budget->dev; 618c2ecf20Sopenharmony_ci dprintk(2, "budget: %p\n", budget); 628c2ecf20Sopenharmony_ci 638c2ecf20Sopenharmony_ci saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); 648c2ecf20Sopenharmony_ci udelay(data ? 500 : 1000); 658c2ecf20Sopenharmony_ci saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); 668c2ecf20Sopenharmony_ci udelay(data ? 1000 : 500); 678c2ecf20Sopenharmony_ci} 688c2ecf20Sopenharmony_ci 698c2ecf20Sopenharmony_cistatic void DiseqcSendByte (struct budget *budget, int data) 708c2ecf20Sopenharmony_ci{ 718c2ecf20Sopenharmony_ci int i, par=1, d; 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ci dprintk(2, "budget: %p\n", budget); 748c2ecf20Sopenharmony_ci 758c2ecf20Sopenharmony_ci for (i=7; i>=0; i--) { 768c2ecf20Sopenharmony_ci d = (data>>i)&1; 778c2ecf20Sopenharmony_ci par ^= d; 788c2ecf20Sopenharmony_ci DiseqcSendBit(budget, d); 798c2ecf20Sopenharmony_ci } 808c2ecf20Sopenharmony_ci 818c2ecf20Sopenharmony_ci DiseqcSendBit(budget, par); 828c2ecf20Sopenharmony_ci} 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_cistatic int SendDiSEqCMsg (struct budget *budget, int len, u8 *msg, unsigned long burst) 858c2ecf20Sopenharmony_ci{ 868c2ecf20Sopenharmony_ci struct saa7146_dev *dev=budget->dev; 878c2ecf20Sopenharmony_ci int i; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci dprintk(2, "budget: %p\n", budget); 908c2ecf20Sopenharmony_ci 918c2ecf20Sopenharmony_ci saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); 928c2ecf20Sopenharmony_ci mdelay(16); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci for (i=0; i<len; i++) 958c2ecf20Sopenharmony_ci DiseqcSendByte(budget, msg[i]); 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci mdelay(16); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (burst!=-1) { 1008c2ecf20Sopenharmony_ci if (burst) 1018c2ecf20Sopenharmony_ci DiseqcSendByte(budget, 0xff); 1028c2ecf20Sopenharmony_ci else { 1038c2ecf20Sopenharmony_ci saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); 1048c2ecf20Sopenharmony_ci mdelay(12); 1058c2ecf20Sopenharmony_ci udelay(500); 1068c2ecf20Sopenharmony_ci saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); 1078c2ecf20Sopenharmony_ci } 1088c2ecf20Sopenharmony_ci msleep(20); 1098c2ecf20Sopenharmony_ci } 1108c2ecf20Sopenharmony_ci 1118c2ecf20Sopenharmony_ci return 0; 1128c2ecf20Sopenharmony_ci} 1138c2ecf20Sopenharmony_ci 1148c2ecf20Sopenharmony_ci/* shamelessly copy/pasted from budget.c */ 1158c2ecf20Sopenharmony_cistatic int budget_set_tone(struct dvb_frontend *fe, 1168c2ecf20Sopenharmony_ci enum fe_sec_tone_mode tone) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci struct budget* budget = (struct budget*) fe->dvb->priv; 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_ci switch (tone) { 1218c2ecf20Sopenharmony_ci case SEC_TONE_ON: 1228c2ecf20Sopenharmony_ci gpio_Set22K (budget, 1); 1238c2ecf20Sopenharmony_ci break; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_ci case SEC_TONE_OFF: 1268c2ecf20Sopenharmony_ci gpio_Set22K (budget, 0); 1278c2ecf20Sopenharmony_ci break; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci default: 1308c2ecf20Sopenharmony_ci return -EINVAL; 1318c2ecf20Sopenharmony_ci } 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci return 0; 1348c2ecf20Sopenharmony_ci} 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_cistatic int budget_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) 1378c2ecf20Sopenharmony_ci{ 1388c2ecf20Sopenharmony_ci struct budget* budget = (struct budget*) fe->dvb->priv; 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci SendDiSEqCMsg (budget, cmd->msg_len, cmd->msg, 0); 1418c2ecf20Sopenharmony_ci 1428c2ecf20Sopenharmony_ci return 0; 1438c2ecf20Sopenharmony_ci} 1448c2ecf20Sopenharmony_ci 1458c2ecf20Sopenharmony_cistatic int budget_diseqc_send_burst(struct dvb_frontend *fe, 1468c2ecf20Sopenharmony_ci enum fe_sec_mini_cmd minicmd) 1478c2ecf20Sopenharmony_ci{ 1488c2ecf20Sopenharmony_ci struct budget* budget = (struct budget*) fe->dvb->priv; 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_ci SendDiSEqCMsg (budget, 0, NULL, minicmd); 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ci return 0; 1538c2ecf20Sopenharmony_ci} 1548c2ecf20Sopenharmony_ci 1558c2ecf20Sopenharmony_cistatic int budget_av7110_send_fw_cmd(struct budget_patch *budget, u16* buf, int length) 1568c2ecf20Sopenharmony_ci{ 1578c2ecf20Sopenharmony_ci int i; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci dprintk(2, "budget: %p\n", budget); 1608c2ecf20Sopenharmony_ci 1618c2ecf20Sopenharmony_ci for (i = 2; i < length; i++) 1628c2ecf20Sopenharmony_ci { 1638c2ecf20Sopenharmony_ci ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2*i, 2, (u32) buf[i], 0,0); 1648c2ecf20Sopenharmony_ci msleep(5); 1658c2ecf20Sopenharmony_ci } 1668c2ecf20Sopenharmony_ci if (length) 1678c2ecf20Sopenharmony_ci ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, (u32) buf[1], 0,0); 1688c2ecf20Sopenharmony_ci else 1698c2ecf20Sopenharmony_ci ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND + 2, 2, 0, 0,0); 1708c2ecf20Sopenharmony_ci msleep(5); 1718c2ecf20Sopenharmony_ci ttpci_budget_debiwrite(budget, DEBINOSWAP, COMMAND, 2, (u32) buf[0], 0,0); 1728c2ecf20Sopenharmony_ci msleep(5); 1738c2ecf20Sopenharmony_ci return 0; 1748c2ecf20Sopenharmony_ci} 1758c2ecf20Sopenharmony_ci 1768c2ecf20Sopenharmony_cistatic void av7110_set22k(struct budget_patch *budget, int state) 1778c2ecf20Sopenharmony_ci{ 1788c2ecf20Sopenharmony_ci u16 buf[2] = {( COMTYPE_AUDIODAC << 8) | (state ? ON22K : OFF22K), 0}; 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci dprintk(2, "budget: %p\n", budget); 1818c2ecf20Sopenharmony_ci budget_av7110_send_fw_cmd(budget, buf, 2); 1828c2ecf20Sopenharmony_ci} 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_cistatic int av7110_send_diseqc_msg(struct budget_patch *budget, int len, u8 *msg, int burst) 1858c2ecf20Sopenharmony_ci{ 1868c2ecf20Sopenharmony_ci int i; 1878c2ecf20Sopenharmony_ci u16 buf[18] = { ((COMTYPE_AUDIODAC << 8) | SendDiSEqC), 1888c2ecf20Sopenharmony_ci 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci dprintk(2, "budget: %p\n", budget); 1918c2ecf20Sopenharmony_ci 1928c2ecf20Sopenharmony_ci if (len>10) 1938c2ecf20Sopenharmony_ci len=10; 1948c2ecf20Sopenharmony_ci 1958c2ecf20Sopenharmony_ci buf[1] = len+2; 1968c2ecf20Sopenharmony_ci buf[2] = len; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci if (burst != -1) 1998c2ecf20Sopenharmony_ci buf[3]=burst ? 0x01 : 0x00; 2008c2ecf20Sopenharmony_ci else 2018c2ecf20Sopenharmony_ci buf[3]=0xffff; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_ci for (i=0; i<len; i++) 2048c2ecf20Sopenharmony_ci buf[i+4]=msg[i]; 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci budget_av7110_send_fw_cmd(budget, buf, 18); 2078c2ecf20Sopenharmony_ci return 0; 2088c2ecf20Sopenharmony_ci} 2098c2ecf20Sopenharmony_ci 2108c2ecf20Sopenharmony_cistatic int budget_patch_set_tone(struct dvb_frontend *fe, 2118c2ecf20Sopenharmony_ci enum fe_sec_tone_mode tone) 2128c2ecf20Sopenharmony_ci{ 2138c2ecf20Sopenharmony_ci struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci switch (tone) { 2168c2ecf20Sopenharmony_ci case SEC_TONE_ON: 2178c2ecf20Sopenharmony_ci av7110_set22k (budget, 1); 2188c2ecf20Sopenharmony_ci break; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci case SEC_TONE_OFF: 2218c2ecf20Sopenharmony_ci av7110_set22k (budget, 0); 2228c2ecf20Sopenharmony_ci break; 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci default: 2258c2ecf20Sopenharmony_ci return -EINVAL; 2268c2ecf20Sopenharmony_ci } 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_ci return 0; 2298c2ecf20Sopenharmony_ci} 2308c2ecf20Sopenharmony_ci 2318c2ecf20Sopenharmony_cistatic int budget_patch_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) 2328c2ecf20Sopenharmony_ci{ 2338c2ecf20Sopenharmony_ci struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; 2348c2ecf20Sopenharmony_ci 2358c2ecf20Sopenharmony_ci av7110_send_diseqc_msg (budget, cmd->msg_len, cmd->msg, 0); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_ci return 0; 2388c2ecf20Sopenharmony_ci} 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_cistatic int budget_patch_diseqc_send_burst(struct dvb_frontend *fe, 2418c2ecf20Sopenharmony_ci enum fe_sec_mini_cmd minicmd) 2428c2ecf20Sopenharmony_ci{ 2438c2ecf20Sopenharmony_ci struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; 2448c2ecf20Sopenharmony_ci 2458c2ecf20Sopenharmony_ci av7110_send_diseqc_msg (budget, 0, NULL, minicmd); 2468c2ecf20Sopenharmony_ci 2478c2ecf20Sopenharmony_ci return 0; 2488c2ecf20Sopenharmony_ci} 2498c2ecf20Sopenharmony_ci 2508c2ecf20Sopenharmony_cistatic int alps_bsrv2_tuner_set_params(struct dvb_frontend *fe) 2518c2ecf20Sopenharmony_ci{ 2528c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 2538c2ecf20Sopenharmony_ci struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; 2548c2ecf20Sopenharmony_ci u8 pwr = 0; 2558c2ecf20Sopenharmony_ci u8 buf[4]; 2568c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; 2578c2ecf20Sopenharmony_ci u32 div = (p->frequency + 479500) / 125; 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci if (p->frequency > 2000000) 2608c2ecf20Sopenharmony_ci pwr = 3; 2618c2ecf20Sopenharmony_ci else if (p->frequency > 1800000) 2628c2ecf20Sopenharmony_ci pwr = 2; 2638c2ecf20Sopenharmony_ci else if (p->frequency > 1600000) 2648c2ecf20Sopenharmony_ci pwr = 1; 2658c2ecf20Sopenharmony_ci else if (p->frequency > 1200000) 2668c2ecf20Sopenharmony_ci pwr = 0; 2678c2ecf20Sopenharmony_ci else if (p->frequency >= 1100000) 2688c2ecf20Sopenharmony_ci pwr = 1; 2698c2ecf20Sopenharmony_ci else pwr = 2; 2708c2ecf20Sopenharmony_ci 2718c2ecf20Sopenharmony_ci buf[0] = (div >> 8) & 0x7f; 2728c2ecf20Sopenharmony_ci buf[1] = div & 0xff; 2738c2ecf20Sopenharmony_ci buf[2] = ((div & 0x18000) >> 10) | 0x95; 2748c2ecf20Sopenharmony_ci buf[3] = (pwr << 6) | 0x30; 2758c2ecf20Sopenharmony_ci 2768c2ecf20Sopenharmony_ci // NOTE: since we're using a prescaler of 2, we set the 2778c2ecf20Sopenharmony_ci // divisor frequency to 62.5kHz and divide by 125 above 2788c2ecf20Sopenharmony_ci 2798c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 2808c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 2818c2ecf20Sopenharmony_ci if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) 2828c2ecf20Sopenharmony_ci return -EIO; 2838c2ecf20Sopenharmony_ci return 0; 2848c2ecf20Sopenharmony_ci} 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_cistatic struct ves1x93_config alps_bsrv2_config = { 2878c2ecf20Sopenharmony_ci .demod_address = 0x08, 2888c2ecf20Sopenharmony_ci .xin = 90100000UL, 2898c2ecf20Sopenharmony_ci .invert_pwm = 0, 2908c2ecf20Sopenharmony_ci}; 2918c2ecf20Sopenharmony_ci 2928c2ecf20Sopenharmony_cistatic int grundig_29504_451_tuner_set_params(struct dvb_frontend *fe) 2938c2ecf20Sopenharmony_ci{ 2948c2ecf20Sopenharmony_ci struct dtv_frontend_properties *p = &fe->dtv_property_cache; 2958c2ecf20Sopenharmony_ci struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; 2968c2ecf20Sopenharmony_ci u32 div; 2978c2ecf20Sopenharmony_ci u8 data[4]; 2988c2ecf20Sopenharmony_ci struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ci div = p->frequency / 125; 3018c2ecf20Sopenharmony_ci data[0] = (div >> 8) & 0x7f; 3028c2ecf20Sopenharmony_ci data[1] = div & 0xff; 3038c2ecf20Sopenharmony_ci data[2] = 0x8e; 3048c2ecf20Sopenharmony_ci data[3] = 0x00; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (fe->ops.i2c_gate_ctrl) 3078c2ecf20Sopenharmony_ci fe->ops.i2c_gate_ctrl(fe, 1); 3088c2ecf20Sopenharmony_ci if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) 3098c2ecf20Sopenharmony_ci return -EIO; 3108c2ecf20Sopenharmony_ci return 0; 3118c2ecf20Sopenharmony_ci} 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_cistatic struct tda8083_config grundig_29504_451_config = { 3148c2ecf20Sopenharmony_ci .demod_address = 0x68, 3158c2ecf20Sopenharmony_ci}; 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_cistatic void frontend_init(struct budget_patch* budget) 3188c2ecf20Sopenharmony_ci{ 3198c2ecf20Sopenharmony_ci switch(budget->dev->pci->subsystem_device) { 3208c2ecf20Sopenharmony_ci case 0x0000: // Hauppauge/TT WinTV DVB-S rev1.X 3218c2ecf20Sopenharmony_ci case 0x1013: // SATELCO Multimedia PCI 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_ci // try the ALPS BSRV2 first of all 3248c2ecf20Sopenharmony_ci budget->dvb_frontend = dvb_attach(ves1x93_attach, &alps_bsrv2_config, &budget->i2c_adap); 3258c2ecf20Sopenharmony_ci if (budget->dvb_frontend) { 3268c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; 3278c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; 3288c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst; 3298c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.set_tone = budget_patch_set_tone; 3308c2ecf20Sopenharmony_ci break; 3318c2ecf20Sopenharmony_ci } 3328c2ecf20Sopenharmony_ci 3338c2ecf20Sopenharmony_ci // try the ALPS BSRU6 now 3348c2ecf20Sopenharmony_ci budget->dvb_frontend = dvb_attach(stv0299_attach, &alps_bsru6_config, &budget->i2c_adap); 3358c2ecf20Sopenharmony_ci if (budget->dvb_frontend) { 3368c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; 3378c2ecf20Sopenharmony_ci budget->dvb_frontend->tuner_priv = &budget->i2c_adap; 3388c2ecf20Sopenharmony_ci 3398c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; 3408c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; 3418c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.set_tone = budget_set_tone; 3428c2ecf20Sopenharmony_ci break; 3438c2ecf20Sopenharmony_ci } 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci // Try the grundig 29504-451 3468c2ecf20Sopenharmony_ci budget->dvb_frontend = dvb_attach(tda8083_attach, &grundig_29504_451_config, &budget->i2c_adap); 3478c2ecf20Sopenharmony_ci if (budget->dvb_frontend) { 3488c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; 3498c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; 3508c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; 3518c2ecf20Sopenharmony_ci budget->dvb_frontend->ops.set_tone = budget_set_tone; 3528c2ecf20Sopenharmony_ci break; 3538c2ecf20Sopenharmony_ci } 3548c2ecf20Sopenharmony_ci break; 3558c2ecf20Sopenharmony_ci } 3568c2ecf20Sopenharmony_ci 3578c2ecf20Sopenharmony_ci if (budget->dvb_frontend == NULL) { 3588c2ecf20Sopenharmony_ci printk("dvb-ttpci: A frontend driver was not found for device [%04x:%04x] subsystem [%04x:%04x]\n", 3598c2ecf20Sopenharmony_ci budget->dev->pci->vendor, 3608c2ecf20Sopenharmony_ci budget->dev->pci->device, 3618c2ecf20Sopenharmony_ci budget->dev->pci->subsystem_vendor, 3628c2ecf20Sopenharmony_ci budget->dev->pci->subsystem_device); 3638c2ecf20Sopenharmony_ci } else { 3648c2ecf20Sopenharmony_ci if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) { 3658c2ecf20Sopenharmony_ci printk("budget-av: Frontend registration failed!\n"); 3668c2ecf20Sopenharmony_ci dvb_frontend_detach(budget->dvb_frontend); 3678c2ecf20Sopenharmony_ci budget->dvb_frontend = NULL; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_ci/* written by Emard */ 3738c2ecf20Sopenharmony_cistatic int budget_patch_attach (struct saa7146_dev* dev, struct saa7146_pci_extension_data *info) 3748c2ecf20Sopenharmony_ci{ 3758c2ecf20Sopenharmony_ci struct budget_patch *budget; 3768c2ecf20Sopenharmony_ci int err; 3778c2ecf20Sopenharmony_ci int count = 0; 3788c2ecf20Sopenharmony_ci int detected = 0; 3798c2ecf20Sopenharmony_ci 3808c2ecf20Sopenharmony_ci#define PATCH_RESET 0 3818c2ecf20Sopenharmony_ci#define RPS_IRQ 0 3828c2ecf20Sopenharmony_ci#define HPS_SETUP 0 3838c2ecf20Sopenharmony_ci#if PATCH_RESET 3848c2ecf20Sopenharmony_ci saa7146_write(dev, MC1, MASK_31); 3858c2ecf20Sopenharmony_ci msleep(40); 3868c2ecf20Sopenharmony_ci#endif 3878c2ecf20Sopenharmony_ci#if HPS_SETUP 3888c2ecf20Sopenharmony_ci // initialize registers. Better to have it like this 3898c2ecf20Sopenharmony_ci // than leaving something unconfigured 3908c2ecf20Sopenharmony_ci saa7146_write(dev, DD1_STREAM_B, 0); 3918c2ecf20Sopenharmony_ci // port B VSYNC at rising edge 3928c2ecf20Sopenharmony_ci saa7146_write(dev, DD1_INIT, 0x00000200); // have this in budget-core too! 3938c2ecf20Sopenharmony_ci saa7146_write(dev, BRS_CTRL, 0x00000000); // VBI 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci // debi config 3968c2ecf20Sopenharmony_ci // saa7146_write(dev, DEBI_CONFIG, MASK_30|MASK_28|MASK_18); 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_ci // zero all HPS registers 3998c2ecf20Sopenharmony_ci saa7146_write(dev, HPS_H_PRESCALE, 0); // r68 4008c2ecf20Sopenharmony_ci saa7146_write(dev, HPS_H_SCALE, 0); // r6c 4018c2ecf20Sopenharmony_ci saa7146_write(dev, BCS_CTRL, 0); // r70 4028c2ecf20Sopenharmony_ci saa7146_write(dev, HPS_V_SCALE, 0); // r60 4038c2ecf20Sopenharmony_ci saa7146_write(dev, HPS_V_GAIN, 0); // r64 4048c2ecf20Sopenharmony_ci saa7146_write(dev, CHROMA_KEY_RANGE, 0); // r74 4058c2ecf20Sopenharmony_ci saa7146_write(dev, CLIP_FORMAT_CTRL, 0); // r78 4068c2ecf20Sopenharmony_ci // Set HPS prescaler for port B input 4078c2ecf20Sopenharmony_ci saa7146_write(dev, HPS_CTRL, (1<<30) | (0<<29) | (1<<28) | (0<<12) ); 4088c2ecf20Sopenharmony_ci saa7146_write(dev, MC2, 4098c2ecf20Sopenharmony_ci 0 * (MASK_08 | MASK_24) | // BRS control 4108c2ecf20Sopenharmony_ci 0 * (MASK_09 | MASK_25) | // a 4118c2ecf20Sopenharmony_ci 0 * (MASK_10 | MASK_26) | // b 4128c2ecf20Sopenharmony_ci 1 * (MASK_06 | MASK_22) | // HPS_CTRL1 4138c2ecf20Sopenharmony_ci 1 * (MASK_05 | MASK_21) | // HPS_CTRL2 4148c2ecf20Sopenharmony_ci 0 * (MASK_01 | MASK_15) // DEBI 4158c2ecf20Sopenharmony_ci ); 4168c2ecf20Sopenharmony_ci#endif 4178c2ecf20Sopenharmony_ci // Disable RPS1 and RPS0 4188c2ecf20Sopenharmony_ci saa7146_write(dev, MC1, ( MASK_29 | MASK_28)); 4198c2ecf20Sopenharmony_ci // RPS1 timeout disable 4208c2ecf20Sopenharmony_ci saa7146_write(dev, RPS_TOV1, 0); 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_ci // code for autodetection 4238c2ecf20Sopenharmony_ci // will wait for VBI_B event (vertical blank at port B) 4248c2ecf20Sopenharmony_ci // and will reset GPIO3 after VBI_B is detected. 4258c2ecf20Sopenharmony_ci // (GPIO3 should be raised high by CPU to 4268c2ecf20Sopenharmony_ci // test if GPIO3 will generate vertical blank signal 4278c2ecf20Sopenharmony_ci // in budget patch GPIO3 is connected to VSYNC_B 4288c2ecf20Sopenharmony_ci count = 0; 4298c2ecf20Sopenharmony_ci#if 0 4308c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_UPLOAD | 4318c2ecf20Sopenharmony_ci MASK_10 | MASK_09 | MASK_08 | MASK_06 | MASK_05 | MASK_04 | MASK_03 | MASK_02 ); 4328c2ecf20Sopenharmony_ci#endif 4338c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | EVT_VBI_B); 4348c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); 4358c2ecf20Sopenharmony_ci WRITE_RPS1(GPIO3_MSK); 4368c2ecf20Sopenharmony_ci WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); 4378c2ecf20Sopenharmony_ci#if RPS_IRQ 4388c2ecf20Sopenharmony_ci // issue RPS1 interrupt to increment counter 4398c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_INTERRUPT); 4408c2ecf20Sopenharmony_ci // at least a NOP is neede between two interrupts 4418c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_NOP); 4428c2ecf20Sopenharmony_ci // interrupt again 4438c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_INTERRUPT); 4448c2ecf20Sopenharmony_ci#endif 4458c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_STOP); 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_ci#if RPS_IRQ 4488c2ecf20Sopenharmony_ci // set event counter 1 source as RPS1 interrupt (0x03) (rE4 p53) 4498c2ecf20Sopenharmony_ci // use 0x03 to track RPS1 interrupts - increase by 1 every gpio3 is toggled 4508c2ecf20Sopenharmony_ci // use 0x15 to track VPE interrupts - increase by 1 every vpeirq() is called 4518c2ecf20Sopenharmony_ci saa7146_write(dev, EC1SSR, (0x03<<2) | 3 ); 4528c2ecf20Sopenharmony_ci // set event counter 1 threshold to maximum allowed value (rEC p55) 4538c2ecf20Sopenharmony_ci saa7146_write(dev, ECT1R, 0x3fff ); 4548c2ecf20Sopenharmony_ci#endif 4558c2ecf20Sopenharmony_ci // Fix VSYNC level 4568c2ecf20Sopenharmony_ci saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); 4578c2ecf20Sopenharmony_ci // Set RPS1 Address register to point to RPS code (r108 p42) 4588c2ecf20Sopenharmony_ci saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); 4598c2ecf20Sopenharmony_ci // Enable RPS1, (rFC p33) 4608c2ecf20Sopenharmony_ci saa7146_write(dev, MC1, (MASK_13 | MASK_29 )); 4618c2ecf20Sopenharmony_ci 4628c2ecf20Sopenharmony_ci 4638c2ecf20Sopenharmony_ci mdelay(50); 4648c2ecf20Sopenharmony_ci saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTHI); 4658c2ecf20Sopenharmony_ci mdelay(150); 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci 4688c2ecf20Sopenharmony_ci if( (saa7146_read(dev, GPIO_CTRL) & 0x10000000) == 0) 4698c2ecf20Sopenharmony_ci detected = 1; 4708c2ecf20Sopenharmony_ci 4718c2ecf20Sopenharmony_ci#if RPS_IRQ 4728c2ecf20Sopenharmony_ci printk("Event Counter 1 0x%04x\n", saa7146_read(dev, EC1R) & 0x3fff ); 4738c2ecf20Sopenharmony_ci#endif 4748c2ecf20Sopenharmony_ci // Disable RPS1 4758c2ecf20Sopenharmony_ci saa7146_write(dev, MC1, ( MASK_29 )); 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci if(detected == 0) 4788c2ecf20Sopenharmony_ci printk("budget-patch not detected or saa7146 in non-default state.\n" 4798c2ecf20Sopenharmony_ci "try enabling resetting of 7146 with MASK_31 in MC1 register\n"); 4808c2ecf20Sopenharmony_ci 4818c2ecf20Sopenharmony_ci else 4828c2ecf20Sopenharmony_ci printk("BUDGET-PATCH DETECTED.\n"); 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci 4858c2ecf20Sopenharmony_ci/* OLD (Original design by Roberto Deza): 4868c2ecf20Sopenharmony_ci** This code will setup the SAA7146_RPS1 to generate a square 4878c2ecf20Sopenharmony_ci** wave on GPIO3, changing when a field (TS_HEIGHT/2 "lines" of 4888c2ecf20Sopenharmony_ci** TS_WIDTH packets) has been acquired on SAA7146_D1B video port; 4898c2ecf20Sopenharmony_ci** then, this GPIO3 output which is connected to the D1B_VSYNC 4908c2ecf20Sopenharmony_ci** input, will trigger the acquisition of the alternate field 4918c2ecf20Sopenharmony_ci** and so on. 4928c2ecf20Sopenharmony_ci** Currently, the TT_budget / WinTV_Nova cards have two ICs 4938c2ecf20Sopenharmony_ci** (74HCT4040, LVC74) for the generation of this VSYNC signal, 4948c2ecf20Sopenharmony_ci** which seems that can be done perfectly without this :-)). 4958c2ecf20Sopenharmony_ci*/ 4968c2ecf20Sopenharmony_ci 4978c2ecf20Sopenharmony_ci/* New design (By Emard) 4988c2ecf20Sopenharmony_ci** this rps1 code will copy internal HS event to GPIO3 pin. 4998c2ecf20Sopenharmony_ci** GPIO3 is in budget-patch hardware connected to port B VSYNC 5008c2ecf20Sopenharmony_ci 5018c2ecf20Sopenharmony_ci** HS is an internal event of 7146, accessible with RPS 5028c2ecf20Sopenharmony_ci** and temporarily raised high every n lines 5038c2ecf20Sopenharmony_ci** (n in defined in the RPS_THRESH1 counter threshold) 5048c2ecf20Sopenharmony_ci** I think HS is raised high on the beginning of the n-th line 5058c2ecf20Sopenharmony_ci** and remains high until this n-th line that triggered 5068c2ecf20Sopenharmony_ci** it is completely received. When the reception of n-th line 5078c2ecf20Sopenharmony_ci** ends, HS is lowered. 5088c2ecf20Sopenharmony_ci 5098c2ecf20Sopenharmony_ci** To transmit data over DMA, 7146 needs changing state at 5108c2ecf20Sopenharmony_ci** port B VSYNC pin. Any changing of port B VSYNC will 5118c2ecf20Sopenharmony_ci** cause some DMA data transfer, with more or less packets loss. 5128c2ecf20Sopenharmony_ci** It depends on the phase and frequency of VSYNC and 5138c2ecf20Sopenharmony_ci** the way of 7146 is instructed to trigger on port B (defined 5148c2ecf20Sopenharmony_ci** in DD1_INIT register, 3rd nibble from the right valid 5158c2ecf20Sopenharmony_ci** numbers are 0-7, see datasheet) 5168c2ecf20Sopenharmony_ci** 5178c2ecf20Sopenharmony_ci** The correct triggering can minimize packet loss, 5188c2ecf20Sopenharmony_ci** dvbtraffic should give this stable bandwidths: 5198c2ecf20Sopenharmony_ci** 22k transponder = 33814 kbit/s 5208c2ecf20Sopenharmony_ci** 27.5k transponder = 38045 kbit/s 5218c2ecf20Sopenharmony_ci** by experiment it is found that the best results 5228c2ecf20Sopenharmony_ci** (stable bandwidths and almost no packet loss) 5238c2ecf20Sopenharmony_ci** are obtained using DD1_INIT triggering number 2 5248c2ecf20Sopenharmony_ci** (Va at rising edge of VS Fa = HS x VS-failing forced toggle) 5258c2ecf20Sopenharmony_ci** and a VSYNC phase that occurs in the middle of DMA transfer 5268c2ecf20Sopenharmony_ci** (about byte 188*512=96256 in the DMA window). 5278c2ecf20Sopenharmony_ci** 5288c2ecf20Sopenharmony_ci** Phase of HS is still not clear to me how to control, 5298c2ecf20Sopenharmony_ci** It just happens to be so. It can be seen if one enables 5308c2ecf20Sopenharmony_ci** RPS_IRQ and print Event Counter 1 in vpeirq(). Every 5318c2ecf20Sopenharmony_ci** time RPS_INTERRUPT is called, the Event Counter 1 will 5328c2ecf20Sopenharmony_ci** increment. That's how the 7146 is programmed to do event 5338c2ecf20Sopenharmony_ci** counting in this budget-patch.c 5348c2ecf20Sopenharmony_ci** I *think* HPS setting has something to do with the phase 5358c2ecf20Sopenharmony_ci** of HS but I can't be 100% sure in that. 5368c2ecf20Sopenharmony_ci 5378c2ecf20Sopenharmony_ci** hardware debug note: a working budget card (including budget patch) 5388c2ecf20Sopenharmony_ci** with vpeirq() interrupt setup in mode "0x90" (every 64K) will 5398c2ecf20Sopenharmony_ci** generate 3 interrupts per 25-Hz DMA frame of 2*188*512 bytes 5408c2ecf20Sopenharmony_ci** and that means 3*25=75 Hz of interrupt frequency, as seen by 5418c2ecf20Sopenharmony_ci** watch cat /proc/interrupts 5428c2ecf20Sopenharmony_ci** 5438c2ecf20Sopenharmony_ci** If this frequency is 3x lower (and data received in the DMA 5448c2ecf20Sopenharmony_ci** buffer don't start with 0x47, but in the middle of packets, 5458c2ecf20Sopenharmony_ci** whose lengths appear to be like 188 292 188 104 etc. 5468c2ecf20Sopenharmony_ci** this means VSYNC line is not connected in the hardware. 5478c2ecf20Sopenharmony_ci** (check soldering pcb and pins) 5488c2ecf20Sopenharmony_ci** The same behaviour of missing VSYNC can be duplicated on budget 5498c2ecf20Sopenharmony_ci** cards, by setting DD1_INIT trigger mode 7 in 3rd nibble. 5508c2ecf20Sopenharmony_ci*/ 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci // Setup RPS1 "program" (p35) 5538c2ecf20Sopenharmony_ci count = 0; 5548c2ecf20Sopenharmony_ci 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci // Wait Source Line Counter Threshold (p36) 5578c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | EVT_HS); 5588c2ecf20Sopenharmony_ci // Set GPIO3=1 (p42) 5598c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); 5608c2ecf20Sopenharmony_ci WRITE_RPS1(GPIO3_MSK); 5618c2ecf20Sopenharmony_ci WRITE_RPS1(SAA7146_GPIO_OUTHI<<24); 5628c2ecf20Sopenharmony_ci#if RPS_IRQ 5638c2ecf20Sopenharmony_ci // issue RPS1 interrupt 5648c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_INTERRUPT); 5658c2ecf20Sopenharmony_ci#endif 5668c2ecf20Sopenharmony_ci // Wait reset Source Line Counter Threshold (p36) 5678c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_PAUSE | RPS_INV | EVT_HS); 5688c2ecf20Sopenharmony_ci // Set GPIO3=0 (p42) 5698c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_WR_REG_MASK | (GPIO_CTRL>>2)); 5708c2ecf20Sopenharmony_ci WRITE_RPS1(GPIO3_MSK); 5718c2ecf20Sopenharmony_ci WRITE_RPS1(SAA7146_GPIO_OUTLO<<24); 5728c2ecf20Sopenharmony_ci#if RPS_IRQ 5738c2ecf20Sopenharmony_ci // issue RPS1 interrupt 5748c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_INTERRUPT); 5758c2ecf20Sopenharmony_ci#endif 5768c2ecf20Sopenharmony_ci // Jump to begin of RPS program (p37) 5778c2ecf20Sopenharmony_ci WRITE_RPS1(CMD_JUMP); 5788c2ecf20Sopenharmony_ci WRITE_RPS1(dev->d_rps1.dma_handle); 5798c2ecf20Sopenharmony_ci 5808c2ecf20Sopenharmony_ci // Fix VSYNC level 5818c2ecf20Sopenharmony_ci saa7146_setgpio(dev, 3, SAA7146_GPIO_OUTLO); 5828c2ecf20Sopenharmony_ci // Set RPS1 Address register to point to RPS code (r108 p42) 5838c2ecf20Sopenharmony_ci saa7146_write(dev, RPS_ADDR1, dev->d_rps1.dma_handle); 5848c2ecf20Sopenharmony_ci 5858c2ecf20Sopenharmony_ci if (!(budget = kmalloc (sizeof(struct budget_patch), GFP_KERNEL))) 5868c2ecf20Sopenharmony_ci return -ENOMEM; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci dprintk(2, "budget: %p\n", budget); 5898c2ecf20Sopenharmony_ci 5908c2ecf20Sopenharmony_ci err = ttpci_budget_init(budget, dev, info, THIS_MODULE, adapter_nr); 5918c2ecf20Sopenharmony_ci if (err) { 5928c2ecf20Sopenharmony_ci kfree(budget); 5938c2ecf20Sopenharmony_ci return err; 5948c2ecf20Sopenharmony_ci } 5958c2ecf20Sopenharmony_ci 5968c2ecf20Sopenharmony_ci // Set Source Line Counter Threshold, using BRS (rCC p43) 5978c2ecf20Sopenharmony_ci // It generates HS event every TS_HEIGHT lines 5988c2ecf20Sopenharmony_ci // this is related to TS_WIDTH set in register 5998c2ecf20Sopenharmony_ci // NUM_LINE_BYTE3 in budget-core.c. If NUM_LINE_BYTE 6008c2ecf20Sopenharmony_ci // low 16 bits are set to TS_WIDTH bytes (TS_WIDTH=2*188 6018c2ecf20Sopenharmony_ci //,then RPS_THRESH1 6028c2ecf20Sopenharmony_ci // should be set to trigger every TS_HEIGHT (512) lines. 6038c2ecf20Sopenharmony_ci // 6048c2ecf20Sopenharmony_ci saa7146_write(dev, RPS_THRESH1, budget->buffer_height | MASK_12 ); 6058c2ecf20Sopenharmony_ci 6068c2ecf20Sopenharmony_ci // saa7146_write(dev, RPS_THRESH0, ((TS_HEIGHT/2)<<16) |MASK_28| (TS_HEIGHT/2) |MASK_12 ); 6078c2ecf20Sopenharmony_ci // Enable RPS1 (rFC p33) 6088c2ecf20Sopenharmony_ci saa7146_write(dev, MC1, (MASK_13 | MASK_29)); 6098c2ecf20Sopenharmony_ci 6108c2ecf20Sopenharmony_ci 6118c2ecf20Sopenharmony_ci dev->ext_priv = budget; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_ci budget->dvb_adapter.priv = budget; 6148c2ecf20Sopenharmony_ci frontend_init(budget); 6158c2ecf20Sopenharmony_ci 6168c2ecf20Sopenharmony_ci ttpci_budget_init_hooks(budget); 6178c2ecf20Sopenharmony_ci 6188c2ecf20Sopenharmony_ci return 0; 6198c2ecf20Sopenharmony_ci} 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int budget_patch_detach (struct saa7146_dev* dev) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct budget_patch *budget = (struct budget_patch*) dev->ext_priv; 6248c2ecf20Sopenharmony_ci int err; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci if (budget->dvb_frontend) { 6278c2ecf20Sopenharmony_ci dvb_unregister_frontend(budget->dvb_frontend); 6288c2ecf20Sopenharmony_ci dvb_frontend_detach(budget->dvb_frontend); 6298c2ecf20Sopenharmony_ci } 6308c2ecf20Sopenharmony_ci err = ttpci_budget_deinit (budget); 6318c2ecf20Sopenharmony_ci 6328c2ecf20Sopenharmony_ci kfree (budget); 6338c2ecf20Sopenharmony_ci 6348c2ecf20Sopenharmony_ci return err; 6358c2ecf20Sopenharmony_ci} 6368c2ecf20Sopenharmony_ci 6378c2ecf20Sopenharmony_cistatic int __init budget_patch_init(void) 6388c2ecf20Sopenharmony_ci{ 6398c2ecf20Sopenharmony_ci return saa7146_register_extension(&budget_extension); 6408c2ecf20Sopenharmony_ci} 6418c2ecf20Sopenharmony_ci 6428c2ecf20Sopenharmony_cistatic void __exit budget_patch_exit(void) 6438c2ecf20Sopenharmony_ci{ 6448c2ecf20Sopenharmony_ci saa7146_unregister_extension(&budget_extension); 6458c2ecf20Sopenharmony_ci} 6468c2ecf20Sopenharmony_ci 6478c2ecf20Sopenharmony_cistatic struct saa7146_extension budget_extension = { 6488c2ecf20Sopenharmony_ci .name = "budget_patch dvb", 6498c2ecf20Sopenharmony_ci .flags = 0, 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci .module = THIS_MODULE, 6528c2ecf20Sopenharmony_ci .pci_tbl = pci_tbl, 6538c2ecf20Sopenharmony_ci .attach = budget_patch_attach, 6548c2ecf20Sopenharmony_ci .detach = budget_patch_detach, 6558c2ecf20Sopenharmony_ci 6568c2ecf20Sopenharmony_ci .irq_mask = MASK_10, 6578c2ecf20Sopenharmony_ci .irq_func = ttpci_budget_irq10_handler, 6588c2ecf20Sopenharmony_ci}; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_cimodule_init(budget_patch_init); 6618c2ecf20Sopenharmony_cimodule_exit(budget_patch_exit); 6628c2ecf20Sopenharmony_ci 6638c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 6648c2ecf20Sopenharmony_ciMODULE_AUTHOR("Emard, Roberto Deza, Holger Waechtler, Michael Hunold, others"); 6658c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Driver for full TS modified DVB-S SAA7146+AV7110 based so-called Budget Patch cards"); 666