From: Michael Hunold - [DVB] dvb-ttusb-dec, dvb-ttusb-budget, skystar2, bt878 + dvb-bt8xx: follow frontend changes in driver - [DVB] DST isn't a real frontend, it's an interface to a frontend microcontroller, so move the hardware dependend stuff to the right place Signed-off-by: Michael Hunold Signed-off-by: Andrew Morton --- /dev/null | 1293 ---------- 25-akpm/drivers/media/dvb/b2c2/skystar2.c | 289 +- 25-akpm/drivers/media/dvb/bt8xx/bt878.c | 23 25-akpm/drivers/media/dvb/bt8xx/dst.c | 1089 ++++++++ 25-akpm/drivers/media/dvb/bt8xx/dst.h | 40 25-akpm/drivers/media/dvb/bt8xx/dst_priv.h | 37 25-akpm/drivers/media/dvb/bt8xx/dvb-bt8xx.c | 312 ++ 25-akpm/drivers/media/dvb/bt8xx/dvb-bt8xx.h | 5 25-akpm/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c | 230 + 25-akpm/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h | 2 25-akpm/drivers/media/dvb/ttusb-dec/ttusb_dec.c | 349 -- 25-akpm/drivers/media/dvb/ttusb-dec/ttusbdecfe.c | 255 + 25-akpm/drivers/media/dvb/ttusb-dec/ttusbdecfe.h | 38 13 files changed, 2203 insertions(+), 1759 deletions(-) diff -puN drivers/media/dvb/b2c2/skystar2.c~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/b2c2/skystar2.c --- 25/drivers/media/dvb/b2c2/skystar2.c~dvb-follow-frontend-changes-in-drivers Thu Nov 18 15:18:02 2004 +++ 25-akpm/drivers/media/dvb/b2c2/skystar2.c Thu Nov 18 15:18:02 2004 @@ -50,6 +50,8 @@ #include "dvbdev.h" #include "demux.h" #include "dvb_net.h" +#include "stv0299.h" +#include "mt352.h" static int debug; @@ -77,6 +79,9 @@ struct dmaq { u8 *buffer; }; +#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9) +#define __iomem +#endif struct adapter { struct pci_dev *pdev; @@ -118,6 +123,9 @@ struct adapter { int pid_count; int whole_bandwidth_count; u32 mac_filter; + + struct dvb_frontend* fe; + int (*fe_sleep)(struct dvb_frontend* fe); }; #define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg) @@ -297,13 +305,6 @@ static int master_xfer(struct i2c_adapte for (i = 0; i < num; i++) { ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i, msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len); - - /* allow only the mt312, mt352 and stv0299 frontends to access the bus */ - if ((msgs[i].addr != 0x0e) && (msgs[i].addr != 0x68) && - (msgs[i].addr != 0x61) && (msgs[i].addr != 0x0f)) { - up(&tmp->i2c_sem); - return -EREMOTEIO; - } } // read command @@ -785,7 +786,7 @@ static int eeprom_read(struct adapter *a return flex_i2c_read(adapter, 0x20000000, 0x50, addr, buf, len); } -u8 calc_lrc(u8 *buf, int len) +static u8 calc_lrc(u8 *buf, int len) { int i; u8 sum; @@ -1773,6 +1774,7 @@ static void free_adapter_object(struct a if (adapter->io_mem) iounmap(adapter->io_mem); + if (adapter != 0) kfree(adapter); } @@ -2024,6 +2026,7 @@ static int dvb_stop_feed(struct dvb_demu return 0; } +#if 0 /* lnb control */ static void set_tuner_tone(struct adapter *adapter, u8 tone) { @@ -2058,6 +2061,7 @@ static void set_tuner_tone(struct adapte write_reg_dw(adapter, 0x200, 0x40ff8000); } } +#endif static void set_tuner_polarity(struct adapter *adapter, u8 polarity) { @@ -2085,6 +2089,7 @@ static void set_tuner_polarity(struct ad write_reg_dw(adapter, 0x204, var); } +#if 0 static void diseqc_send_bit(struct adapter *adapter, int data) { set_tuner_tone(adapter, 1); @@ -2135,7 +2140,7 @@ static int send_diseqc_msg(struct adapte } -int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg) +static int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg) { switch (cmd) { case FE_SET_TONE: @@ -2169,107 +2174,252 @@ int soft_diseqc(struct adapter *adapter, return 0; } +#endif -static int flexcop_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) +static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { - struct adapter *adapter = fe->before_after_data; - - struct dvb_frontend_info info; + struct adapter* adapter = (struct adapter*) fe->dvb->priv; - fe->ioctl(fe, FE_GET_INFO, &info); + dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); - // we must use different DiSEqC hw + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13); + set_tuner_polarity(adapter, 1); + return 0; - if (strcmp(info.name, "Zarlink MT312") == 0) { - //VP310 using mt312 driver for tuning only: diseqc not wired - //use FCII instead - if (!soft_diseqc(adapter, cmd, arg)) + case SEC_VOLTAGE_18: + dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18); + set_tuner_polarity(adapter, 2); return 0; + + default: + return -EINVAL; + } } - switch (cmd) { - case FE_SLEEP: +static int flexcop_sleep(struct dvb_frontend* fe) { - dprintk("%s: FE_SLEEP\n", __FUNCTION__); + struct adapter* adapter = (struct adapter*) fe->dvb->priv; + dprintk("%s: FE_SLEEP\n", __FUNCTION__); set_tuner_polarity(adapter, 0); - // return -EOPNOTSUPP, to make DVB core also send "FE_SLEEP" command to frontend. - return -EOPNOTSUPP; + if (adapter->fe_sleep) return adapter->fe_sleep(fe); + return 0; } - case FE_SET_VOLTAGE: +static u32 flexcop_i2c_func(struct i2c_adapter *adapter) { - dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); - - switch ((fe_sec_voltage_t) arg) { - case SEC_VOLTAGE_13: + printk("flexcop_i2c_func\n"); - dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13); + return I2C_FUNC_I2C; +} - set_tuner_polarity(adapter, 1); +static struct i2c_algorithm flexcop_algo = { + .name = "flexcop i2c algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = master_xfer, + .functionality = flexcop_i2c_func, +}; - return 0; - case SEC_VOLTAGE_18: - dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18); - set_tuner_polarity(adapter, 2); +static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ratio) +{ + u8 aclk = 0; + u8 bclk = 0; - return 0; + if (srate < 1500000) { aclk = 0xb7; bclk = 0x47; } + else if (srate < 3000000) { aclk = 0xb7; bclk = 0x4b; } + else if (srate < 7000000) { aclk = 0xb7; bclk = 0x4f; } + else if (srate < 14000000) { aclk = 0xb7; bclk = 0x53; } + else if (srate < 30000000) { aclk = 0xb6; bclk = 0x53; } + else if (srate < 45000000) { aclk = 0xb4; bclk = 0x51; } + + stv0299_writereg (fe, 0x13, aclk); + stv0299_writereg (fe, 0x14, bclk); + stv0299_writereg (fe, 0x1f, (ratio >> 16) & 0xff); + stv0299_writereg (fe, 0x20, (ratio >> 8) & 0xff); + stv0299_writereg (fe, 0x21, (ratio ) & 0xf0); - default: + return 0; +} - return -EINVAL; - }; - } +static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; + struct adapter* adapter = (struct adapter*) fe->dvb->priv; + div = params->frequency / 125; - default: + buf[0] = (div >> 8) & 0x7f; + buf[1] = div & 0xff; + buf[2] = 0x84; // 0xC4 + buf[3] = 0x08; - return -EOPNOTSUPP; - }; + if (params->frequency < 1500000) buf[3] |= 0x10; + if (i2c_transfer (&adapter->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } +static u8 samsung_tbmu24112_inittab[] = { + 0x01, 0x15, + 0x02, 0x30, + 0x03, 0x00, + 0x04, 0x7D, + 0x05, 0x35, + 0x06, 0x02, + 0x07, 0x00, + 0x08, 0xC3, + 0x0C, 0x00, + 0x0D, 0x81, + 0x0E, 0x23, + 0x0F, 0x12, + 0x10, 0x7E, + 0x11, 0x84, + 0x12, 0xB9, + 0x13, 0x88, + 0x14, 0x89, + 0x15, 0xC9, + 0x16, 0x00, + 0x17, 0x5C, + 0x18, 0x00, + 0x19, 0x00, + 0x1A, 0x00, + 0x1C, 0x00, + 0x1D, 0x00, + 0x1E, 0x00, + 0x1F, 0x3A, + 0x20, 0x2E, + 0x21, 0x80, + 0x22, 0xFF, + 0x23, 0xC1, + 0x28, 0x00, + 0x29, 0x1E, + 0x2A, 0x14, + 0x2B, 0x0F, + 0x2C, 0x09, + 0x2D, 0x05, + 0x31, 0x1F, + 0x32, 0x19, + 0x33, 0xFE, + 0x34, 0x93, + 0xff, 0xff, + }; + +static struct stv0299_config samsung_tbmu24112_config = { + .demod_address = 0x68, + .inittab = samsung_tbmu24112_inittab, + .mclk = 88000000UL, + .invert = 0, + .enhanced_tuning = 0, + .skip_reinit = 0, + .lock_output = STV0229_LOCKOUTPUT_LK, + .volt13_op0_op1 = STV0299_VOLT13_OP1, + .min_delay_ms = 100, + .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, + .pll_set = samsung_tbmu24112_pll_set, +}; + + + + -static int client_register(struct i2c_client *client) +static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) { - struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter); + static u8 mt352_clock_config [] = { 0x89, 0x10, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0xa1 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); - dprintk("client_register\n"); + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); - if (client->driver->command) - return client->driver->command(client, FE_REGISTER, adapter->dvb_adapter); return 0; } -static int client_unregister(struct i2c_client *client) +int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) { - struct adapter *adapter = (struct adapter*)i2c_get_adapdata(client->adapter); + u32 div; + unsigned char bs = 0; - dprintk("client_unregister\n"); + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency >= 48000000 && params->frequency <= 154000000) bs = 0x09; + if (params->frequency >= 161000000 && params->frequency <= 439000000) bs = 0x0a; + if (params->frequency >= 447000000 && params->frequency <= 863000000) bs = 0x08; + + pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = 0xcc; + pllbuf[4] = bs; - if (client->driver->command) - return client->driver->command(client, FE_UNREGISTER, adapter->dvb_adapter); return 0; } -u32 flexcop_i2c_func(struct i2c_adapter *adapter) +static struct mt352_config samsung_tdtc9251dh0_config = { + + .demod_address = 0x0f, + .demod_init = samsung_tdtc9251dh0_demod_init, + .pll_set = samsung_tdtc9251dh0_pll_set, +}; + + + + + +static void frontend_init(struct adapter *skystar2) { - printk("flexcop_i2c_func\n"); + switch(skystar2->pdev->device) { + case 0x2103: // Technisat Skystar2 OR Technisat Airstar2 - return I2C_FUNC_I2C; + // try the skystar2 first (stv0299/Samsung tbmu24112(sl1935)) + skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap); + if (skystar2->fe != NULL) { + skystar2->fe->ops->set_voltage = flexcop_set_voltage; + skystar2->fe_sleep = skystar2->fe->ops->sleep; + skystar2->fe->ops->sleep = flexcop_sleep; + break; } -static struct i2c_algorithm flexcop_algo = { - .name = "flexcop i2c algorithm", - .id = I2C_ALGO_BIT, - .master_xfer = master_xfer, - .functionality = flexcop_i2c_func, -}; + // try the airstar2 (mt352/Samsung tdtc9251dh0(??)) + skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap); + if (skystar2->fe != NULL) { + skystar2->fe->ops->info.frequency_min = 474000000; + skystar2->fe->ops->info.frequency_max = 858000000; + break; + } + break; + } + + if (skystar2->fe == NULL) { + printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + skystar2->pdev->vendor, + skystar2->pdev->device, + skystar2->pdev->subsystem_vendor, + skystar2->pdev->subsystem_device); + } else { + if (dvb_register_frontend(skystar2->dvb_adapter, skystar2->fe)) { + printk("skystar2: Frontend registration failed!\n"); + if (skystar2->fe->ops->release) + skystar2->fe->ops->release(skystar2->fe); + skystar2->fe = NULL; + } + } +} static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent) @@ -2298,8 +2448,10 @@ static int skystar2_probe(struct pci_dev adapter = (struct adapter *) pci_get_drvdata(pdev); + dvb_adapter->priv = adapter; adapter->dvb_adapter = dvb_adapter; + init_MUTEX(&adapter->i2c_sem); @@ -2316,16 +2468,12 @@ static int skystar2_probe(struct pci_dev adapter->i2c_adap.algo = &flexcop_algo; adapter->i2c_adap.algo_data = NULL; adapter->i2c_adap.id = I2C_ALGO_BIT; - adapter->i2c_adap.client_register = client_register; - adapter->i2c_adap.client_unregister = client_unregister; if (i2c_add_adapter(&adapter->i2c_adap) < 0) { dvb_unregister_adapter (adapter->dvb_adapter); return -ENOMEM; } - dvb_add_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL, adapter); - dvbdemux = &adapter->demux; dvbdemux->priv = (void *) adapter; @@ -2361,6 +2509,9 @@ static int skystar2_probe(struct pci_dev return ret; dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx); + + frontend_init(adapter); + return 0; } @@ -2385,9 +2536,9 @@ static void skystar2_remove(struct pci_d dvb_dmxdev_release(&adapter->dmxdev); dvb_dmx_release(&adapter->demux); - if (adapter->dvb_adapter != NULL) { - dvb_remove_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL); + if (adapter->fe != NULL) dvb_unregister_frontend(adapter->fe); + if (adapter->dvb_adapter != NULL) { i2c_del_adapter(&adapter->i2c_adap); dvb_unregister_adapter(adapter->dvb_adapter); @@ -2398,7 +2549,7 @@ static void skystar2_remove(struct pci_d static struct pci_device_id skystar2_pci_tbl[] = { {0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, - {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, //FCIII +/* {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */ //FCIII {0,}, }; diff -puN drivers/media/dvb/bt8xx/bt878.c~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/bt8xx/bt878.c --- 25/drivers/media/dvb/bt8xx/bt878.c~dvb-follow-frontend-changes-in-drivers Thu Nov 18 15:18:02 2004 +++ 25-akpm/drivers/media/dvb/bt8xx/bt878.c Thu Nov 18 15:18:02 2004 @@ -44,7 +44,7 @@ #include "dmxdev.h" #include "dvbdev.h" #include "bt878.h" -#include "dst-bt878.h" +#include "dst_priv.h" /**************************************/ @@ -559,22 +559,11 @@ static struct pci_driver bt878_pci_drive static int bt878_pci_driver_registered = 0; -/* This will be used later by dvb-bt8xx to only use the audio - * dma of certain cards */ -int bt878_find_audio_dma(void) -{ - // pci_register_driver(&bt878_pci_driver); - bt878_pci_driver_registered = 1; - return 0; -} - -EXPORT_SYMBOL(bt878_find_audio_dma); - /*******************************/ /* Module management functions */ /*******************************/ -int bt878_init_module(void) +static int bt878_init_module(void) { bt878_num = 0; bt878_pci_driver_registered = 0; @@ -586,13 +575,13 @@ int bt878_init_module(void) /* bt878_check_chipset(); */ - /* later we register inside of bt878_find_audio_dma + /* later we register inside of bt878_find_audio_dma() * because we may want to ignore certain cards */ bt878_pci_driver_registered = 1; return pci_module_init(&bt878_pci_driver); } -void bt878_cleanup_module(void) +static void bt878_cleanup_module(void) { if (bt878_pci_driver_registered) { bt878_pci_driver_registered = 0; @@ -601,12 +590,10 @@ void bt878_cleanup_module(void) return; } -EXPORT_SYMBOL(bt878_init_module); -EXPORT_SYMBOL(bt878_cleanup_module); module_init(bt878_init_module); module_exit(bt878_cleanup_module); - +//MODULE_AUTHOR("XXX"); MODULE_LICENSE("GPL"); /* diff -puN /dev/null drivers/media/dvb/bt8xx/dst.c --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/drivers/media/dvb/bt8xx/dst.c Thu Nov 18 15:18:02 2004 @@ -0,0 +1,1089 @@ +/* + Frontend-driver for TwinHan DST Frontend + + Copyright (C) 2003 Jamie Honan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dvb_frontend.h" +#include "dst_priv.h" +#include "dst.h" + +struct dst_state { + + struct i2c_adapter* i2c; + + struct bt878* bt; + + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct dst_config* config; + + struct dvb_frontend frontend; + + /* private demodulator data */ + u8 tx_tuna[10]; + u8 rx_tuna[10]; + u8 rxbuffer[10]; + u8 diseq_flags; + u8 dst_type; + u32 type_flags; + u32 frequency; /* intermediate frequency in kHz for QPSK */ + fe_spectral_inversion_t inversion; + u32 symbol_rate; /* symbol rate in Symbols per second */ + fe_code_rate_t fec; + fe_sec_voltage_t voltage; + fe_sec_tone_mode_t tone; + u32 decode_freq; + u8 decode_lock; + u16 decode_strength; + u16 decode_snr; + unsigned long cur_jiff; + u8 k22; + fe_bandwidth_t bandwidth; +}; + +static unsigned int dst_verbose = 0; +module_param(dst_verbose, int, 0644); +MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)"); +static unsigned int dst_debug = 0; +module_param(dst_debug, int, 0644); +MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)"); + +#define dprintk if (dst_debug) printk + +#define DST_TYPE_IS_SAT 0 +#define DST_TYPE_IS_TERR 1 +#define DST_TYPE_IS_CABLE 2 + +#define DST_TYPE_HAS_NEWTUNE 1 +#define DST_TYPE_HAS_TS204 2 +#define DST_TYPE_HAS_SYMDIV 4 + +#define HAS_LOCK 1 +#define ATTEMPT_TUNE 2 +#define HAS_POWER 4 + +static void dst_packsize(struct dst_state* state, int psize) +{ + union dst_gpio_packet bits; + + bits.psize = psize; + bt878_device_control(state->bt, DST_IG_TS, &bits); +} + +static int dst_gpio_outb(struct dst_state* state, u32 mask, u32 enbb, u32 outhigh) +{ + union dst_gpio_packet enb; + union dst_gpio_packet bits; + int err; + + enb.enb.mask = mask; + enb.enb.enable = enbb; + if ((err = bt878_device_control(state->bt, DST_IG_ENABLE, &enb)) < 0) { + dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb); + return -EREMOTEIO; + } + + /* because complete disabling means no output, no need to do output packet */ + if (enbb == 0) + return 0; + + bits.outp.mask = enbb; + bits.outp.highvals = outhigh; + + if ((err = bt878_device_control(state->bt, DST_IG_WRITE, &bits)) < 0) { + dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh); + return -EREMOTEIO; + } + return 0; +} + +static int dst_gpio_inb(struct dst_state *state, u8 * result) +{ + union dst_gpio_packet rd_packet; + int err; + + *result = 0; + + if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { + dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err); + return -EREMOTEIO; + } + + *result = (u8) rd_packet.rd.value; + return 0; +} + +#define DST_I2C_ENABLE 1 +#define DST_8820 2 + +static int dst_reset8820(struct dst_state *state) +{ + int retval; + /* pull 8820 gpio pin low, wait, high, wait, then low */ + // dprintk ("%s: reset 8820\n", __FUNCTION__); + retval = dst_gpio_outb(state, DST_8820, DST_8820, 0); + if (retval < 0) + return retval; + msleep(10); + retval = dst_gpio_outb(state, DST_8820, DST_8820, DST_8820); + if (retval < 0) + return retval; + /* wait for more feedback on what works here * + msleep(10); + retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0); + if (retval < 0) + return retval; + */ + return 0; +} + +static int dst_i2c_enable(struct dst_state *state) +{ + int retval; + /* pull I2C enable gpio pin low, wait */ + // dprintk ("%s: i2c enable\n", __FUNCTION__); + retval = dst_gpio_outb(state, ~0, DST_I2C_ENABLE, 0); + if (retval < 0) + return retval; + // dprintk ("%s: i2c enable delay\n", __FUNCTION__); + msleep(33); + return 0; +} + +static int dst_i2c_disable(struct dst_state *state) +{ + int retval; + /* release I2C enable gpio pin, wait */ + // dprintk ("%s: i2c disable\n", __FUNCTION__); + retval = dst_gpio_outb(state, ~0, 0, 0); + if (retval < 0) + return retval; + // dprintk ("%s: i2c disable delay\n", __FUNCTION__); + msleep(33); + return 0; +} + +static int dst_wait_dst_ready(struct dst_state *state) +{ + u8 reply; + int retval; + int i; + for (i = 0; i < 200; i++) { + retval = dst_gpio_inb(state, &reply); + if (retval < 0) + return retval; + if ((reply & DST_I2C_ENABLE) == 0) { + dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i); + return 1; + } + msleep(10); + } + dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i); + return 0; +} + +static int write_dst(struct dst_state *state, u8 * data, u8 len) +{ + struct i2c_msg msg = { + .addr = state->config->demod_address,.flags = 0,.buf = data,.len = len + }; + int err; + int cnt; + + if (dst_debug && dst_verbose) { + u8 i; + dprintk("%s writing", __FUNCTION__); + for (i = 0; i < len; i++) { + dprintk(" 0x%02x", data[i]); + } + dprintk("\n"); + } + msleep(30); + for (cnt = 0; cnt < 4; cnt++) { + if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { + dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]); + dst_i2c_disable(state); + msleep(500); + dst_i2c_enable(state); + msleep(500); + continue; + } else + break; + } + if (cnt >= 4) + return -EREMOTEIO; + return 0; +} + +static int read_dst(struct dst_state *state, u8 * ret, u8 len) +{ + struct i2c_msg msg = {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = ret,.len = len }; + int err; + int cnt; + + for (cnt = 0; cnt < 4; cnt++) { + if ((err = i2c_transfer(state->i2c, &msg, 1)) < 0) { + dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]); + dst_i2c_disable(state); + dst_i2c_enable(state); + continue; + } else + break; + } + if (cnt >= 4) + return -EREMOTEIO; + dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]); + if (dst_debug && dst_verbose) { + for (err = 1; err < len; err++) + dprintk(" 0x%x", ret[err]); + if (err > 1) + dprintk("\n"); + } + return 0; +} + +static int dst_set_freq(struct dst_state *state, u32 freq) +{ + u8 *val; + + state->frequency = freq; + + // dprintk("%s: set frequency %u\n", __FUNCTION__, freq); + if (state->dst_type == DST_TYPE_IS_SAT) { + freq = freq / 1000; + if (freq < 950 || freq > 2150) + return -EINVAL; + val = &state->tx_tuna[0]; + val[2] = (freq >> 8) & 0x7f; + val[3] = (u8) freq; + val[4] = 1; + val[8] &= ~4; + if (freq < 1531) + val[8] |= 4; + } else if (state->dst_type == DST_TYPE_IS_TERR) { + freq = freq / 1000; + if (freq < 137000 || freq > 858000) + return -EINVAL; + val = &state->tx_tuna[0]; + val[2] = (freq >> 16) & 0xff; + val[3] = (freq >> 8) & 0xff; + val[4] = (u8) freq; + val[5] = 0; + switch (state->bandwidth) { + case BANDWIDTH_6_MHZ: + val[6] = 6; + break; + + case BANDWIDTH_7_MHZ: + case BANDWIDTH_AUTO: + val[6] = 7; + break; + + case BANDWIDTH_8_MHZ: + val[6] = 8; + break; + } + + val[7] = 0; + val[8] = 0; + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + /* guess till will get one */ + freq = freq / 1000; + val = &state->tx_tuna[0]; + val[2] = (freq >> 16) & 0xff; + val[3] = (freq >> 8) & 0xff; + val[4] = (u8) freq; + } else + return -EINVAL; + return 0; +} + +static int dst_set_bandwidth(struct dst_state* state, fe_bandwidth_t bandwidth) +{ + u8 *val; + + state->bandwidth = bandwidth; + + if (state->dst_type != DST_TYPE_IS_TERR) + return 0; + + val = &state->tx_tuna[0]; + switch (bandwidth) { + case BANDWIDTH_6_MHZ: + val[6] = 6; + break; + + case BANDWIDTH_7_MHZ: + val[6] = 7; + break; + + case BANDWIDTH_8_MHZ: + val[6] = 8; + break; + + default: + return -EINVAL; + } + return 0; +} + +static int dst_set_inversion(struct dst_state* state, fe_spectral_inversion_t inversion) +{ + u8 *val; + + state->inversion = inversion; + + val = &state->tx_tuna[0]; + + val[8] &= ~0x80; + + switch (inversion) { + case INVERSION_OFF: + break; + case INVERSION_ON: + val[8] |= 0x80; + break; + default: + return -EINVAL; + } + return 0; +} + +static int dst_set_fec(struct dst_state* state, fe_code_rate_t fec) +{ + state->fec = fec; + return 0; +} + +static fe_code_rate_t dst_get_fec(struct dst_state* state) +{ + return state->fec; +} + +static int dst_set_symbolrate(struct dst_state* state, u32 srate) +{ + u8 *val; + u32 symcalc; + u64 sval; + + state->symbol_rate = srate; + + if (state->dst_type == DST_TYPE_IS_TERR) { + return 0; + } + // dprintk("%s: set srate %u\n", __FUNCTION__, srate); + srate /= 1000; + val = &state->tx_tuna[0]; + + if (state->type_flags & DST_TYPE_HAS_SYMDIV) { + sval = srate; + sval <<= 20; + do_div(sval, 88000); + symcalc = (u32) sval; + // dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc); + val[5] = (u8) (symcalc >> 12); + val[6] = (u8) (symcalc >> 4); + val[7] = (u8) (symcalc << 4); + } else { + val[5] = (u8) (srate >> 16) & 0x7f; + val[6] = (u8) (srate >> 8); + val[7] = (u8) srate; + } + val[8] &= ~0x20; + if (srate > 8000) + val[8] |= 0x20; + return 0; +} + +static u8 dst_check_sum(u8 * buf, u32 len) +{ + u32 i; + u8 val = 0; + if (!len) + return 0; + for (i = 0; i < len; i++) { + val += buf[i]; + } + return ((~val) + 1); +} + +struct dst_types { + char *mstr; + int offs; + u8 dst_type; + u32 type_flags; +}; + +static struct dst_types dst_tlist[] = { + {"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV}, + {"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE}, + {"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204}, + {"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV}, + {"DST-CI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE}, + {"DSTMCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE}, + {"DSTFCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE}, + {"DCTNEW", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE}, + {"DCT-CI", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204}, + {"DTTDIG", 1, DST_TYPE_IS_TERR, 0} +}; + +/* DCTNEW and DCT-CI are guesses */ + +static void dst_type_flags_print(u32 type_flags) +{ + printk("DST type flags :"); + if (type_flags & DST_TYPE_HAS_NEWTUNE) + printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE); + if (type_flags & DST_TYPE_HAS_TS204) + printk(" 0x%x ts204", DST_TYPE_HAS_TS204); + if (type_flags & DST_TYPE_HAS_SYMDIV) + printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV); + printk("\n"); +} + +static int dst_type_print(u8 type) +{ + char *otype; + switch (type) { + case DST_TYPE_IS_SAT: + otype = "satellite"; + break; + case DST_TYPE_IS_TERR: + otype = "terrestial TV"; + break; + case DST_TYPE_IS_CABLE: + otype = "terrestial TV"; + break; + default: + printk("%s: invalid dst type %d\n", __FUNCTION__, type); + return -EINVAL; + } + printk("DST type : %s\n", otype); + return 0; +} + +static int dst_check_ci(struct dst_state *state) +{ + u8 txbuf[8]; + u8 rxbuf[8]; + int retval; + int i; + struct dst_types *dsp; + u8 use_dst_type; + u32 use_type_flags; + + memset(txbuf, 0, sizeof(txbuf)); + txbuf[1] = 6; + txbuf[7] = dst_check_sum(txbuf, 7); + + dst_i2c_enable(state); + dst_reset8820(state); + retval = write_dst(state, txbuf, 8); + if (retval < 0) { + dst_i2c_disable(state); + dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__); + return retval; + } + msleep(3); + retval = read_dst(state, rxbuf, 1); + dst_i2c_disable(state); + if (retval < 0) { + dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__); + return retval; + } + if (rxbuf[0] != 0xff) { + dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]); + return retval; + } + if (!dst_wait_dst_ready(state)) + return 0; + // dst_i2c_enable(i2c); Dimitri + retval = read_dst(state, rxbuf, 8); + dst_i2c_disable(state); + if (retval < 0) { + dprintk("%s: read not successful\n", __FUNCTION__); + return retval; + } + if (rxbuf[7] != dst_check_sum(rxbuf, 7)) { + dprintk("%s: checksum failure\n", __FUNCTION__); + return retval; + } + rxbuf[7] = '\0'; + for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) { + if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) { + use_type_flags = dsp->type_flags; + use_dst_type = dsp->dst_type; + printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr); + break; + } + } + if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) { + printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]); + printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__); + use_dst_type = DST_TYPE_IS_SAT; + use_type_flags = DST_TYPE_HAS_SYMDIV; + } + dst_type_print(use_dst_type); + + state->type_flags = use_type_flags; + state->dst_type = use_dst_type; + dst_type_flags_print(state->type_flags); + + if (state->type_flags & DST_TYPE_HAS_TS204) { + dst_packsize(state, 204); + } + return 0; +} + +static int dst_command(struct dst_state* state, u8 * data, u8 len) +{ + int retval; + u8 reply; + + dst_i2c_enable(state); + dst_reset8820(state); + retval = write_dst(state, data, len); + if (retval < 0) { + dst_i2c_disable(state); + dprintk("%s: write not successful\n", __FUNCTION__); + return retval; + } + msleep(33); + retval = read_dst(state, &reply, 1); + dst_i2c_disable(state); + if (retval < 0) { + dprintk("%s: read verify not successful\n", __FUNCTION__); + return retval; + } + if (reply != 0xff) { + dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply); + return 0; + } + if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) + return 0; + if (!dst_wait_dst_ready(state)) + return 0; + // dst_i2c_enable(i2c); Per dimitri + retval = read_dst(state, state->rxbuffer, 8); + dst_i2c_disable(state); + if (retval < 0) { + dprintk("%s: read not successful\n", __FUNCTION__); + return 0; + } + if (state->rxbuffer[7] != dst_check_sum(state->rxbuffer, 7)) { + dprintk("%s: checksum failure\n", __FUNCTION__); + return 0; + } + return 0; +} + +static int dst_get_signal(struct dst_state* state) +{ + int retval; + u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; + + if ((state->diseq_flags & ATTEMPT_TUNE) == 0) { + state->decode_lock = state->decode_strength = state->decode_snr = 0; + return 0; + } + if (0 == (state->diseq_flags & HAS_LOCK)) { + state->decode_lock = state->decode_strength = state->decode_snr = 0; + return 0; + } + if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) { + retval = dst_command(state, get_signal, 8); + if (retval < 0) + return retval; + if (state->dst_type == DST_TYPE_IS_SAT) { + state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0; + state->decode_strength = state->rxbuffer[5] << 8; + state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; + } else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) { + state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; + state->decode_strength = state->rxbuffer[4] << 8; + state->decode_snr = state->rxbuffer[3] << 8; + } + state->cur_jiff = jiffies; + } + return 0; +} + +static int dst_tone_power_cmd(struct dst_state* state) +{ + u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; + + if (state->dst_type == DST_TYPE_IS_TERR) + return 0; + + if (state->voltage == SEC_VOLTAGE_OFF) + paket[4] = 0; + else + paket[4] = 1; + if (state->tone == SEC_TONE_ON) + paket[2] = state->k22; + else + paket[2] = 0; + paket[7] = dst_check_sum(&paket[0], 7); + dst_command(state, paket, 8); + return 0; +} + +static int dst_get_tuna(struct dst_state* state) +{ + int retval; + if ((state->diseq_flags & ATTEMPT_TUNE) == 0) + return 0; + state->diseq_flags &= ~(HAS_LOCK); + if (!dst_wait_dst_ready(state)) + return 0; + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + /* how to get variable length reply ???? */ + retval = read_dst(state, state->rx_tuna, 10); + } else { + retval = read_dst(state, &state->rx_tuna[2], 8); + } + if (retval < 0) { + dprintk("%s: read not successful\n", __FUNCTION__); + return 0; + } + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { + dprintk("%s: checksum failure?\n", __FUNCTION__); + return 0; + } + } else { + if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[2], 7)) { + dprintk("%s: checksum failure?\n", __FUNCTION__); + return 0; + } + } + if (state->rx_tuna[2] == 0 && state->rx_tuna[3] == 0) + return 0; + state->decode_freq = ((state->rx_tuna[2] & 0x7f) << 8) + state->rx_tuna[3]; + + state->decode_lock = 1; + /* + dst->decode_n1 = (dst->rx_tuna[4] << 8) + + (dst->rx_tuna[5]); + + dst->decode_n2 = (dst->rx_tuna[8] << 8) + + (dst->rx_tuna[7]); + */ + state->diseq_flags |= HAS_LOCK; + /* dst->cur_jiff = jiffies; */ + return 1; +} + +static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage); + +static int dst_write_tuna(struct dvb_frontend* fe) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + int retval; + u8 reply; + + dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags); + state->decode_freq = 0; + state->decode_lock = state->decode_strength = state->decode_snr = 0; + if (state->dst_type == DST_TYPE_IS_SAT) { + if (!(state->diseq_flags & HAS_POWER)) + dst_set_voltage(fe, SEC_VOLTAGE_13); + } + state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); + dst_i2c_enable(state); + if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + dst_reset8820(state); + state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); + retval = write_dst(state, &state->tx_tuna[0], 10); + } else { + state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7); + retval = write_dst(state, &state->tx_tuna[2], 8); + } + if (retval < 0) { + dst_i2c_disable(state); + dprintk("%s: write not successful\n", __FUNCTION__); + return retval; + } + msleep(3); + retval = read_dst(state, &reply, 1); + dst_i2c_disable(state); + if (retval < 0) { + dprintk("%s: read verify not successful\n", __FUNCTION__); + return retval; + } + if (reply != 0xff) { + dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply); + return 0; + } + state->diseq_flags |= ATTEMPT_TUNE; + return dst_get_tuna(state); +} + +/* + * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 + * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 + * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 + * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 + * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 + * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 + * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 + * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec + * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 + * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 + * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 + */ + +static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; + + if (state->dst_type == DST_TYPE_IS_TERR) + return 0; + + if (cmd->msg_len == 0 || cmd->msg_len > 4) + return -EINVAL; + memcpy(&paket[3], cmd->msg, cmd->msg_len); + paket[7] = dst_check_sum(&paket[0], 7); + dst_command(state, paket, 8); + return 0; +} + +static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + u8 *val; + int need_cmd; + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + state->voltage = voltage; + + if (state->dst_type == DST_TYPE_IS_TERR) + return 0; + + need_cmd = 0; + val = &state->tx_tuna[0]; + val[8] &= ~0x40; + switch (voltage) { + case SEC_VOLTAGE_13: + if ((state->diseq_flags & HAS_POWER) == 0) + need_cmd = 1; + state->diseq_flags |= HAS_POWER; + break; + case SEC_VOLTAGE_18: + if ((state->diseq_flags & HAS_POWER) == 0) + need_cmd = 1; + state->diseq_flags |= HAS_POWER; + val[8] |= 0x40; + break; + case SEC_VOLTAGE_OFF: + need_cmd = 1; + state->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); + break; + default: + return -EINVAL; + } + if (need_cmd) { + dst_tone_power_cmd(state); + } + return 0; +} + +static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + u8 *val; + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + state->tone = tone; + + if (state->dst_type == DST_TYPE_IS_TERR) + return 0; + + val = &state->tx_tuna[0]; + + val[8] &= ~0x1; + + switch (tone) { + case SEC_TONE_OFF: + break; + case SEC_TONE_ON: + val[8] |= 1; + break; + default: + return -EINVAL; + } + dst_tone_power_cmd(state); + return 0; +} + +static int dst_init(struct dvb_frontend* fe) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 }; + static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 }; + static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; + static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; + static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; + static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; + state->inversion = INVERSION_ON; + state->voltage = SEC_VOLTAGE_13; + state->tone = SEC_TONE_OFF; + state->symbol_rate = 29473000; + state->fec = FEC_AUTO; + state->diseq_flags = 0; + state->k22 = 0x02; + state->bandwidth = BANDWIDTH_7_MHZ; + state->cur_jiff = jiffies; + if (state->dst_type == DST_TYPE_IS_SAT) { + state->frequency = 950000; + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna)); + } else if (state->dst_type == DST_TYPE_IS_TERR) { + state->frequency = 137000000; + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna)); + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + state->frequency = 51000000; + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna)); + } + + return 0; +} + +static int dst_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + *status = 0; + if (state->diseq_flags & HAS_LOCK) { + dst_get_signal(state); + if (state->decode_lock) + *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; + } + + return 0; +} + +static int dst_read_signal_strength(struct dvb_frontend* fe, u16* strength) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + dst_get_signal(state); + *strength = state->decode_strength; + + return 0; +} + +static int dst_read_snr(struct dvb_frontend* fe, u16* snr) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + dst_get_signal(state); + *snr = state->decode_snr; + + return 0; +} + +static int dst_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + dst_set_freq(state, p->frequency); + dst_set_inversion(state, p->inversion); + if (state->dst_type == DST_TYPE_IS_SAT) { + dst_set_fec(state, p->u.qpsk.fec_inner); + dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + } else if (state->dst_type == DST_TYPE_IS_TERR) { + dst_set_bandwidth(state, p->u.ofdm.bandwidth); + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + dst_set_fec(state, p->u.qam.fec_inner); + dst_set_symbolrate(state, p->u.qam.symbol_rate); + } + dst_write_tuna(fe); + + return 0; +} + +static int dst_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + + p->frequency = state->decode_freq; + p->inversion = state->inversion; + if (state->dst_type == DST_TYPE_IS_SAT) { + p->u.qpsk.symbol_rate = state->symbol_rate; + p->u.qpsk.fec_inner = dst_get_fec(state); + } else if (state->dst_type == DST_TYPE_IS_TERR) { + p->u.ofdm.bandwidth = state->bandwidth; + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + p->u.qam.symbol_rate = state->symbol_rate; + p->u.qam.fec_inner = dst_get_fec(state); + p->u.qam.modulation = QAM_AUTO; + } + + return 0; +} + +static void dst_release(struct dvb_frontend* fe) +{ + struct dst_state* state = (struct dst_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops dst_dvbt_ops; +static struct dvb_frontend_ops dst_dvbs_ops; +static struct dvb_frontend_ops dst_dvbc_ops; + +struct dvb_frontend* dst_attach(const struct dst_config* config, + struct i2c_adapter* i2c, + struct bt878 *bt) +{ + struct dst_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct dst_state*) kmalloc(sizeof(struct dst_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->i2c = i2c; + state->bt = bt; + + /* check if the demod is there */ + if (dst_check_ci(state) < 0) goto error; + + /* determine settings based on type */ + switch (state->dst_type) { + case DST_TYPE_IS_TERR: + memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_CABLE: + memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_SAT: + memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); + break; + default: + printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n"); + goto error; + } + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops dst_dvbt_ops = { + + .info = { + .name = "DST DVB-T", + .type = FE_OFDM, + .frequency_min = 137000000, + .frequency_max = 858000000, + .frequency_stepsize = 166667, + .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO + }, + + .release = dst_release, + + .init = dst_init, + + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +static struct dvb_frontend_ops dst_dvbs_ops = { + + .info = { + .name = "DST DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 1000, /* kHz for QPSK frontends */ + .frequency_tolerance = 29500, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* . symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK + }, + + .release = dst_release, + + .init = dst_init, + + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, + + .diseqc_send_master_cmd = dst_set_diseqc, + .set_voltage = dst_set_voltage, + .set_tone = dst_set_tone, +}; + +static struct dvb_frontend_ops dst_dvbc_ops = { + + .info = { + .name = "DST DVB-C", + .type = FE_QAM, + .frequency_stepsize = 62500, + .frequency_min = 51000000, + .frequency_max = 858000000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + /* . symbol_rate_tolerance = ???,*/ + .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO + }, + + .release = dst_release, + + .init = dst_init, + + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +MODULE_DESCRIPTION("DST DVB-S/T/C Combo Frontend driver"); +MODULE_AUTHOR("Jamie Honan"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(dst_attach); diff -puN /dev/null drivers/media/dvb/bt8xx/dst.h --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/drivers/media/dvb/bt8xx/dst.h Thu Nov 18 15:18:02 2004 @@ -0,0 +1,40 @@ +/* + Frontend-driver for TwinHan DST Frontend + + Copyright (C) 2003 Jamie Honan + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +*/ + +#ifndef DST_H +#define DST_H + +#include +#include +#include "bt878.h" + +struct dst_config +{ + /* the demodulator's i2c address */ + u8 demod_address; +}; + +extern struct dvb_frontend* dst_attach(const struct dst_config* config, + struct i2c_adapter* i2c, + struct bt878 *bt); + +#endif // DST_H diff -puN /dev/null drivers/media/dvb/bt8xx/dst_priv.h --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/drivers/media/dvb/bt8xx/dst_priv.h Thu Nov 18 15:18:02 2004 @@ -0,0 +1,37 @@ +/* + * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend + * + * Copyright (C) 2003 Jamie Honan + */ + +struct dst_gpio_enable { + u32 mask; + u32 enable; +}; + +struct dst_gpio_output { + u32 mask; + u32 highvals; +}; + +struct dst_gpio_read { + unsigned long value; +}; + +union dst_gpio_packet { + struct dst_gpio_enable enb; + struct dst_gpio_output outp; + struct dst_gpio_read rd; + int psize; +}; + +#define DST_IG_ENABLE 0 +#define DST_IG_WRITE 1 +#define DST_IG_READ 2 +#define DST_IG_TS 3 + +struct bt878; + +int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp); + +struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adap); diff -puN drivers/media/dvb/bt8xx/dvb-bt8xx.c~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/bt8xx/dvb-bt8xx.c --- 25/drivers/media/dvb/bt8xx/dvb-bt8xx.c~dvb-follow-frontend-changes-in-drivers Thu Nov 18 15:18:02 2004 +++ 25-akpm/drivers/media/dvb/bt8xx/dvb-bt8xx.c Thu Nov 18 15:18:02 2004 @@ -126,7 +126,286 @@ static struct bt878 __init *dvb_bt8xx_87 return NULL; } -static int __init dvb_bt8xx_load_card( struct dvb_bt8xx_card *card) + +static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x38 }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x28, 0x20 }; + static u8 mt352_gpp_ctl_cfg [] = { 0x75, 0x33 }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + + mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg)); + mt352_write(fe, mt352_gpp_ctl_cfg, sizeof(mt352_gpp_ctl_cfg)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +{ + u32 div; + unsigned char bs = 0; + unsigned char cp = 0; + + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency < 542000000) cp = 0xb4; + else if (params->frequency < 771000000) cp = 0xbc; + else cp = 0xf4; + + if (params->frequency == 0) bs = 0x03; + else if (params->frequency < 443250000) bs = 0x02; + else bs = 0x08; + + pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = cp; + pllbuf[4] = bs; + + return 0; +} + +static struct mt352_config thomson_dtt7579_config = { + + .demod_address = 0x0f, + .demod_init = thomson_dtt7579_demod_init, + .pll_set = thomson_dtt7579_pll_set, +}; + + + +static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; + u8 cfg, cpump, band_select; + u8 data[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = data, .len = sizeof(data) }; + + div = (36000000 + params->frequency + 83333) / 166666; + cfg = 0x88; + + if (params->frequency < 175000000) cpump = 2; + else if (params->frequency < 390000000) cpump = 1; + else if (params->frequency < 470000000) cpump = 2; + else if (params->frequency < 750000000) cpump = 2; + else cpump = 3; + + if (params->frequency < 175000000) band_select = 0x0e; + else if (params->frequency < 470000000) band_select = 0x05; + else band_select = 0x03; + + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | cfg; + data[3] = cpump | band_select; + + i2c_transfer(card->i2c_adapter, &msg, 1); + return (div * 166666 - 36000000); +} + +static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct dvb_bt8xx_card* bt = (struct dvb_bt8xx_card*) fe->dvb->priv; + + return request_firmware(fw, name, &bt->bt->dev->dev); +} + +struct sp887x_config microtune_mt7202dtf_config = { + + .demod_address = 0x70, + .pll_set = microtune_mt7202dtf_pll_set, + .request_firmware = microtune_mt7202dtf_request_firmware, +}; + + + +static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) +{ + static u8 mt352_clock_config [] = { 0x89, 0x38, 0x2d }; + static u8 mt352_reset [] = { 0x50, 0x80 }; + static u8 mt352_adc_ctl_1_cfg [] = { 0x8E, 0x40 }; + static u8 mt352_agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF, + 0x00, 0xFF, 0x00, 0x40, 0x40 }; + static u8 mt352_av771_extra[] = { 0xB5, 0x7A }; + static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 }; + + + mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config)); + udelay(2000); + mt352_write(fe, mt352_reset, sizeof(mt352_reset)); + mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg)); + + mt352_write(fe, mt352_agc_cfg,sizeof(mt352_agc_cfg)); + udelay(2000); + mt352_write(fe, mt352_av771_extra,sizeof(mt352_av771_extra)); + mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg)); + + return 0; +} + +static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +{ + u32 div; + unsigned char bs = 0; + unsigned char cp = 0; + + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; + + if (params->frequency < 150000000) cp = 0xB4; + else if (params->frequency < 173000000) cp = 0xBC; + else if (params->frequency < 250000000) cp = 0xB4; + else if (params->frequency < 400000000) cp = 0xBC; + else if (params->frequency < 420000000) cp = 0xF4; + else if (params->frequency < 470000000) cp = 0xFC; + else if (params->frequency < 600000000) cp = 0xBC; + else if (params->frequency < 730000000) cp = 0xF4; + else cp = 0xFC; + + if (params->frequency < 150000000) bs = 0x01; + else if (params->frequency < 173000000) bs = 0x01; + else if (params->frequency < 250000000) bs = 0x02; + else if (params->frequency < 400000000) bs = 0x02; + else if (params->frequency < 420000000) bs = 0x02; + else if (params->frequency < 470000000) bs = 0x02; + else if (params->frequency < 600000000) bs = 0x08; + else if (params->frequency < 730000000) bs = 0x08; + else bs = 0x08; + + pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address + pllbuf[1] = div >> 8; + pllbuf[2] = div & 0xff; + pllbuf[3] = cp; + pllbuf[4] = bs; + + return 0; +} + +static struct mt352_config advbt771_samsung_tdtc9251dh0_config = { + + .demod_address = 0x0f, + .demod_init = advbt771_samsung_tdtc9251dh0_demod_init, + .pll_set = advbt771_samsung_tdtc9251dh0_pll_set, +}; + + +static struct dst_config dst_config = { + + .demod_address = 0x55, +}; + + +static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; + u8 buf[4]; + u32 div; + struct i2c_msg msg = { .addr = 0x60, .flags = 0, .buf = buf, .len = sizeof(buf) }; + + div = (params->frequency + 36166667) / 166667; + + buf[0] = (div >> 8) & 0x7F; + buf[1] = div & 0xFF; + buf[2] = 0x85; + if ((params->frequency >= 47000000) && (params->frequency < 153000000)) + buf[3] = 0x01; + else if ((params->frequency >= 153000000) && (params->frequency < 430000000)) + buf[3] = 0x02; + else if ((params->frequency >= 430000000) && (params->frequency < 824000000)) + buf[3] = 0x0C; + else if ((params->frequency >= 824000000) && (params->frequency < 863000000)) + buf[3] = 0x8C; + else + return -EINVAL; + + i2c_transfer(card->i2c_adapter, &msg, 1); + return 0; +} + +static struct nxt6000_config vp3021_alps_tded4_config = { + + .demod_address = 0x0a, + .clock_inversion = 1, + .pll_set = vp3021_alps_tded4_pll_set, +}; + + +static void frontend_init(struct dvb_bt8xx_card *card, u32 type) +{ + switch(type) { +#ifdef BTTV_DVICO_DVBT_LITE + case BTTV_DVICO_DVBT_LITE: + card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter); + if (card->fe != NULL) { + card->fe->ops->info.frequency_min = 174000000; + card->fe->ops->info.frequency_max = 862000000; + break; + } + break; +#endif + +#ifdef BTTV_TWINHAN_VP3021 + case BTTV_TWINHAN_VP3021: +#else + case BTTV_NEBULA_DIGITV: +#endif + card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter); + if (card->fe != NULL) { + break; + } + break; + + case BTTV_AVDVBT_761: + card->fe = sp887x_attach(µtune_mt7202dtf_config, card->i2c_adapter); + if (card->fe != NULL) { + break; + } + break; + + case BTTV_AVDVBT_771: + card->fe = mt352_attach(&advbt771_samsung_tdtc9251dh0_config, card->i2c_adapter); + if (card->fe != NULL) { + card->fe->ops->info.frequency_min = 174000000; + card->fe->ops->info.frequency_max = 862000000; + break; + } + break; + + case BTTV_TWINHAN_DST: + card->fe = dst_attach(&dst_config, card->i2c_adapter, card->bt); + if (card->fe != NULL) { + break; + } + break; + } + + if (card->fe == NULL) { + printk("dvb-bt8xx: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n", + card->bt->dev->vendor, + card->bt->dev->device, + card->bt->dev->subsystem_vendor, + card->bt->dev->subsystem_device); + } else { + if (dvb_register_frontend(card->dvb_adapter, card->fe)) { + printk("dvb-bt8xx: Frontend registration failed!\n"); + if (card->fe->ops->release) + card->fe->ops->release(card->fe); + card->fe = NULL; + } + } +} + +static int __init dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) { int result; @@ -136,6 +415,7 @@ static int __init dvb_bt8xx_load_card( s return result; } + card->dvb_adapter->priv = card; card->bt->adapter = card->i2c_adapter; @@ -207,6 +487,8 @@ static int __init dvb_bt8xx_load_card( s tasklet_init(&card->bt->tasklet, dvb_bt8xx_task, (unsigned long) card); + frontend_init(card, type); + return 0; } @@ -228,7 +510,7 @@ static int dvb_bt8xx_probe(struct device switch(sub->core->type) { - case BTTV_PINNACLESAT: +/* case BTTV_PINNACLESAT: UNDEFINED HARDWARE */ #ifdef BTTV_DVICO_DVBT_LITE case BTTV_DVICO_DVBT_LITE: #endif @@ -240,7 +522,11 @@ static int dvb_bt8xx_probe(struct device * DA_APP(parallel) */ break; +#ifdef BTTV_TWINHAN_VP3021 + case BTTV_TWINHAN_VP3021: +#else case BTTV_NEBULA_DIGITV: +#endif case BTTV_AVDVBT_761: card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5); card->op_sync_orin = 0; @@ -302,7 +588,7 @@ static int dvb_bt8xx_probe(struct device init_MUTEX(&card->bt->gpio_lock); card->bt->bttv_nr = sub->core->nr; - if ( (ret = dvb_bt8xx_load_card(card)) ) { + if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) { kfree(card); return ret; } @@ -324,6 +610,7 @@ static int dvb_bt8xx_remove(struct devic card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw); dvb_dmxdev_release(&card->dmxdev); dvb_dmx_release(&card->demux); + if (card->fe) dvb_unregister_frontend(card->fe); dvb_unregister_adapter(card->dvb_adapter); kfree(card); @@ -331,24 +618,6 @@ static int dvb_bt8xx_remove(struct devic return 0; } -static void dvb_bt8xx_i2c_info(struct bttv_sub_device *sub, - struct i2c_client *client, int attach) -{ - struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev); - - if (attach) { - printk("xxx attach\n"); - if (client->driver->command) - client->driver->command(client, FE_REGISTER, - card->dvb_adapter); - } else { - printk("xxx detach\n"); - if (client->driver->command) - client->driver->command(client, FE_UNREGISTER, - card->dvb_adapter); - } -} - static struct bttv_sub_driver driver = { .drv = { .name = "dvb-bt8xx", @@ -360,7 +629,6 @@ static struct bttv_sub_driver driver = { * .resume = dvb_bt8xx_resume, */ }, - .i2c_info = dvb_bt8xx_i2c_info, }; static int __init dvb_bt8xx_init(void) diff -puN drivers/media/dvb/bt8xx/dvb-bt8xx.h~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/bt8xx/dvb-bt8xx.h --- 25/drivers/media/dvb/bt8xx/dvb-bt8xx.h~dvb-follow-frontend-changes-in-drivers Thu Nov 18 15:18:02 2004 +++ 25-akpm/drivers/media/dvb/bt8xx/dvb-bt8xx.h Thu Nov 18 15:18:02 2004 @@ -26,6 +26,10 @@ #include "dvbdev.h" #include "dvb_net.h" #include "bttv.h" +#include "mt352.h" +#include "sp887x.h" +#include "dst.h" +#include "nxt6000.h" struct dvb_bt8xx_card { struct semaphore lock; @@ -44,4 +48,5 @@ struct dvb_bt8xx_card { struct i2c_adapter *i2c_adapter; struct dvb_net dvbnet; + struct dvb_frontend* fe; }; diff -L drivers/media/dvb/frontends/dst-bt878.h -puN drivers/media/dvb/frontends/dst-bt878.h~dvb-follow-frontend-changes-in-drivers /dev/null --- 25/drivers/media/dvb/frontends/dst-bt878.h +++ /dev/null Thu Apr 11 07:25:15 2002 @@ -1,37 +0,0 @@ -/* - * dst-bt878.h: part of the DST driver for the TwinHan DST Frontend - * - * Copyright (C) 2003 Jamie Honan - */ - -struct dst_gpio_enable { - u32 mask; - u32 enable; -}; - -struct dst_gpio_output { - u32 mask; - u32 highvals; -}; - -struct dst_gpio_read { - unsigned long value; -}; - -union dst_gpio_packet { - struct dst_gpio_enable enb; - struct dst_gpio_output outp; - struct dst_gpio_read rd; - int psize; -}; - -#define DST_IG_ENABLE 0 -#define DST_IG_WRITE 1 -#define DST_IG_READ 2 -#define DST_IG_TS 3 - -struct bt878 ; - -int bt878_device_control(struct bt878 *bt, unsigned int cmd, union dst_gpio_packet *mp); - -struct bt878 *bt878_find_by_i2c_adap(struct i2c_adapter *adap); diff -L drivers/media/dvb/frontends/dst.c -puN drivers/media/dvb/frontends/dst.c~dvb-follow-frontend-changes-in-drivers /dev/null --- 25/drivers/media/dvb/frontends/dst.c +++ /dev/null Thu Apr 11 07:25:15 2002 @@ -1,1256 +0,0 @@ -/* - Frontend-driver for TwinHan DST Frontend - - Copyright (C) 2003 Jamie Honan - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "dvb_frontend.h" -#include "dst-bt878.h" - -unsigned int dst_verbose = 0; -MODULE_PARM(dst_verbose, "i"); -MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)"); -unsigned int dst_debug = 0; -MODULE_PARM(dst_debug, "i"); -MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)"); - -#define dprintk if (dst_debug) printk - -#define DST_I2C_ADDR 0x55 - -#define DST_TYPE_IS_SAT 0 -#define DST_TYPE_IS_TERR 1 -#define DST_TYPE_IS_CABLE 2 - -#define DST_TYPE_HAS_NEWTUNE 1 -#define DST_TYPE_HAS_TS204 2 -#define DST_TYPE_HAS_SYMDIV 4 - -#define HAS_LOCK 1 -#define ATTEMPT_TUNE 2 -#define HAS_POWER 4 - -struct dst_data { - u8 tx_tuna[10]; - u8 rx_tuna[10]; - u8 rxbuffer[10]; - u8 diseq_flags; - u8 dst_type; - u32 type_flags; - u32 frequency; /* intermediate frequency in kHz for QPSK */ - fe_spectral_inversion_t inversion; - u32 symbol_rate; /* symbol rate in Symbols per second */ - fe_code_rate_t fec; - fe_sec_voltage_t voltage; - fe_sec_tone_mode_t tone; - u32 decode_freq; - u8 decode_lock; - u16 decode_strength; - u16 decode_snr; - unsigned long cur_jiff; - u8 k22; - fe_bandwidth_t bandwidth; - - struct bt878 *bt; - struct i2c_adapter *i2c; - struct dvb_adapter *dvb; -}; - -static struct dvb_frontend_info dst_info_sat = { - .name = "DST SAT", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 1000, /* kHz for QPSK frontends */ - .frequency_tolerance = 29500, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, -/* . symbol_rate_tolerance = ???,*/ - .notifier_delay = 50, /* 1/20 s */ - .caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK -}; - -static struct dvb_frontend_info dst_info_cable = { - .name = "DST CABLE", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 51000000, - .frequency_max = 858000000, - .symbol_rate_min = 1000000, - .symbol_rate_max = 45000000, -/* . symbol_rate_tolerance = ???,*/ - .notifier_delay = 50, /* 1/20 s */ - .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO -}; - -static struct dvb_frontend_info dst_info_terr = { - .name = "DST TERR", - .type = FE_OFDM, - .frequency_min = 137000000, - .frequency_max = 858000000, - .frequency_stepsize = 166667, - .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO -}; - -static void dst_packsize(struct dst_data *dst, int psize) -{ - union dst_gpio_packet bits; - - bits.psize = psize; - bt878_device_control(dst->bt, DST_IG_TS, &bits); -} - -static int dst_gpio_outb(struct dst_data *dst, u32 mask, u32 enbb, u32 outhigh) -{ - union dst_gpio_packet enb; - union dst_gpio_packet bits; - int err; - - enb.enb.mask = mask; - enb.enb.enable = enbb; - if ((err = bt878_device_control(dst->bt, DST_IG_ENABLE, &enb)) < 0) { - dprintk("%s: dst_gpio_enb error (err == %i, mask == 0x%02x, enb == 0x%02x)\n", __FUNCTION__, err, mask, enbb); - return -EREMOTEIO; - } - - /* because complete disabling means no output, no need to do output packet */ - if (enbb == 0) - return 0; - - bits.outp.mask = enbb; - bits.outp.highvals = outhigh; - - if ((err = bt878_device_control(dst->bt, DST_IG_WRITE, &bits)) < 0) { - dprintk("%s: dst_gpio_outb error (err == %i, enbb == 0x%02x, outhigh == 0x%02x)\n", __FUNCTION__, err, enbb, outhigh); - return -EREMOTEIO; - } - return 0; -} - -static int dst_gpio_inb(struct dst_data *dst, u8 * result) -{ - union dst_gpio_packet rd_packet; - int err; - - *result = 0; - - if ((err = bt878_device_control(dst->bt, DST_IG_READ, &rd_packet)) < 0) { - dprintk("%s: dst_gpio_inb error (err == %i)\n", __FUNCTION__, err); - return -EREMOTEIO; - } - *result = (u8) rd_packet.rd.value; - return 0; -} - -#define DST_I2C_ENABLE 1 -#define DST_8820 2 - -static int dst_reset8820(struct dst_data *dst) -{ - int retval; - /* pull 8820 gpio pin low, wait, high, wait, then low */ - // dprintk ("%s: reset 8820\n", __FUNCTION__); - retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0); - if (retval < 0) - return retval; - msleep(10); - retval = dst_gpio_outb(dst, DST_8820, DST_8820, DST_8820); - if (retval < 0) - return retval; - /* wait for more feedback on what works here * - msleep(10); - retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0); - if (retval < 0) - return retval; - */ - return 0; -} - -static int dst_i2c_enable(struct dst_data *dst) -{ - int retval; - /* pull I2C enable gpio pin low, wait */ - // dprintk ("%s: i2c enable\n", __FUNCTION__); - retval = dst_gpio_outb(dst, ~0, DST_I2C_ENABLE, 0); - if (retval < 0) - return retval; - // dprintk ("%s: i2c enable delay\n", __FUNCTION__); - msleep(33); - return 0; -} - -static int dst_i2c_disable(struct dst_data *dst) -{ - int retval; - /* release I2C enable gpio pin, wait */ - // dprintk ("%s: i2c disable\n", __FUNCTION__); - retval = dst_gpio_outb(dst, ~0, 0, 0); - if (retval < 0) - return retval; - // dprintk ("%s: i2c disable delay\n", __FUNCTION__); - msleep(33); - return 0; -} - -static int dst_wait_dst_ready(struct dst_data *dst) -{ - u8 reply; - int retval; - int i; - for (i = 0; i < 200; i++) { - retval = dst_gpio_inb(dst, &reply); - if (retval < 0) - return retval; - if ((reply & DST_I2C_ENABLE) == 0) { - dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i); - return 1; - } - msleep(5); - } - dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i); - return 0; -} - -static int write_dst(struct dst_data *dst, u8 * data, u8 len) -{ - struct i2c_msg msg = { - .addr = DST_I2C_ADDR,.flags = 0,.buf = data,.len = len - }; - int err; - int cnt; - - if (dst_debug && dst_verbose) { - u8 i; - dprintk("%s writing", __FUNCTION__); - for (i = 0; i < len; i++) { - dprintk(" 0x%02x", data[i]); - } - dprintk("\n"); - } - msleep(30); - for (cnt = 0; cnt < 4; cnt++) { - if ((err = i2c_transfer(dst->i2c, &msg, 1)) < 0) { - dprintk("%s: write_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, data[0]); - dst_i2c_disable(dst); - msleep(500); - dst_i2c_enable(dst); - msleep(500); - continue; - } else - break; - } - if (cnt >= 4) - return -EREMOTEIO; - return 0; -} - -static int read_dst(struct dst_data *dst, u8 * ret, u8 len) -{ - struct i2c_msg msg = {.addr = DST_I2C_ADDR,.flags = I2C_M_RD,.buf = ret,.len = len }; - int err; - int cnt; - - for (cnt = 0; cnt < 4; cnt++) { - if ((err = i2c_transfer(dst->i2c, &msg, 1)) < 0) { - dprintk("%s: read_dst error (err == %i, len == 0x%02x, b0 == 0x%02x)\n", __FUNCTION__, err, len, ret[0]); - dst_i2c_disable(dst); - dst_i2c_enable(dst); - continue; - } else - break; - } - if (cnt >= 4) - return -EREMOTEIO; - dprintk("%s reply is 0x%x\n", __FUNCTION__, ret[0]); - if (dst_debug && dst_verbose) { - for (err = 1; err < len; err++) - dprintk(" 0x%x", ret[err]); - if (err > 1) - dprintk("\n"); - } - return 0; -} - -static int dst_set_freq(struct dst_data *dst, u32 freq) -{ - u8 *val; - - dst->frequency = freq; - - // dprintk("%s: set frequency %u\n", __FUNCTION__, freq); - if (dst->dst_type == DST_TYPE_IS_SAT) { - freq = freq / 1000; - if (freq < 950 || freq > 2150) - return -EINVAL; - val = &dst->tx_tuna[0]; - val[2] = (freq >> 8) & 0x7f; - val[3] = (u8) freq; - val[4] = 1; - val[8] &= ~4; - if (freq < 1531) - val[8] |= 4; - } else if (dst->dst_type == DST_TYPE_IS_TERR) { - freq = freq / 1000; - if (freq < 137000 || freq > 858000) - return -EINVAL; - val = &dst->tx_tuna[0]; - val[2] = (freq >> 16) & 0xff; - val[3] = (freq >> 8) & 0xff; - val[4] = (u8) freq; - val[5] = 0; - switch (dst->bandwidth) { - case BANDWIDTH_6_MHZ: - val[6] = 6; - break; - - case BANDWIDTH_7_MHZ: - case BANDWIDTH_AUTO: - val[6] = 7; - break; - - case BANDWIDTH_8_MHZ: - val[6] = 8; - break; - } - - val[7] = 0; - val[8] = 0; - } else if (dst->dst_type == DST_TYPE_IS_CABLE) { - /* guess till will get one */ - freq = freq / 1000; - val = &dst->tx_tuna[0]; - val[2] = (freq >> 16) & 0xff; - val[3] = (freq >> 8) & 0xff; - val[4] = (u8) freq; - } else - return -EINVAL; - return 0; -} - -static int dst_set_bandwidth(struct dst_data *dst, fe_bandwidth_t bandwidth) -{ - u8 *val; - - dst->bandwidth = bandwidth; - - if (dst->dst_type != DST_TYPE_IS_TERR) - return 0; - - val = &dst->tx_tuna[0]; - switch (bandwidth) { - case BANDWIDTH_6_MHZ: - val[6] = 6; - break; - - case BANDWIDTH_7_MHZ: - val[6] = 7; - break; - - case BANDWIDTH_8_MHZ: - val[6] = 8; - break; - - default: - return -EINVAL; - } - return 0; -} - -static int dst_set_inversion(struct dst_data *dst, fe_spectral_inversion_t inversion) -{ - u8 *val; - - dst->inversion = inversion; - - val = &dst->tx_tuna[0]; - - val[8] &= ~0x80; - - switch (inversion) { - case INVERSION_OFF: - break; - case INVERSION_ON: - val[8] |= 0x80; - break; - default: - return -EINVAL; - } - return 0; -} - - -static int dst_set_fec(struct dst_data *dst, fe_code_rate_t fec) -{ - dst->fec = fec; - return 0; -} - -static fe_code_rate_t dst_get_fec(struct dst_data *dst) -{ - return dst->fec; -} - -static int dst_set_symbolrate(struct dst_data *dst, u32 srate) -{ - u8 *val; - u32 symcalc; - u64 sval; - - dst->symbol_rate = srate; - - if (dst->dst_type == DST_TYPE_IS_TERR) { - return 0; - } - // dprintk("%s: set srate %u\n", __FUNCTION__, srate); - srate /= 1000; - val = &dst->tx_tuna[0]; - - if (dst->type_flags & DST_TYPE_HAS_SYMDIV) { - sval = srate; - sval <<= 20; - do_div(sval, 88000); - symcalc = (u32) sval; - // dprintk("%s: set symcalc %u\n", __FUNCTION__, symcalc); - val[5] = (u8) (symcalc >> 12); - val[6] = (u8) (symcalc >> 4); - val[7] = (u8) (symcalc << 4); - } else { - val[5] = (u8) (srate >> 16) & 0x7f; - val[6] = (u8) (srate >> 8); - val[7] = (u8) srate; - } - val[8] &= ~0x20; - if (srate > 8000) - val[8] |= 0x20; - return 0; -} - - -static u8 dst_check_sum(u8 * buf, u32 len) -{ - u32 i; - u8 val = 0; - if (!len) - return 0; - for (i = 0; i < len; i++) { - val += buf[i]; - } - return ((~val) + 1); -} - -typedef struct dst_types { - char *mstr; - int offs; - u8 dst_type; - u32 type_flags; -} DST_TYPES; - -struct dst_types dst_tlist[] = { - {"DST-020", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV}, - {"DST-030", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE}, - {"DST-03T", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204}, - {"DST-MOT", 0, DST_TYPE_IS_SAT, DST_TYPE_HAS_SYMDIV}, - {"DST-CI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE}, - {"DSTMCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE}, - {"DSTFCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE}, - {"DCTNEW", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE}, - {"DCT_CI", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204}, - {"DTTDIG", 1, DST_TYPE_IS_TERR, 0} -}; - -/* DCTNEW and DCT-CI are guesses */ - -static void dst_type_flags_print(u32 type_flags) -{ - printk("DST type flags :"); - if (type_flags & DST_TYPE_HAS_NEWTUNE) - printk(" 0x%x newtuner", DST_TYPE_HAS_NEWTUNE); - if (type_flags & DST_TYPE_HAS_TS204) - printk(" 0x%x ts204", DST_TYPE_HAS_TS204); - if (type_flags & DST_TYPE_HAS_SYMDIV) - printk(" 0x%x symdiv", DST_TYPE_HAS_SYMDIV); - printk("\n"); -} - -static int dst_type_print(u8 type) -{ - char *otype; - switch (type) { - case DST_TYPE_IS_SAT: - otype = "satellite"; - break; - case DST_TYPE_IS_TERR: - otype = "terrestial TV"; - break; - case DST_TYPE_IS_CABLE: - otype = "terrestial TV"; - break; - default: - printk("%s: invalid dst type %d\n", __FUNCTION__, type); - return -EINVAL; - } - printk("DST type : %s\n", otype); - return 0; -} - -static int dst_check_ci(struct dst_data *dst) -{ - u8 txbuf[8]; - u8 rxbuf[8]; - int retval; - int i; - struct dst_types *dsp; - u8 use_dst_type; - u32 use_type_flags; - - memset(txbuf, 0, sizeof(txbuf)); - txbuf[1] = 6; - txbuf[7] = dst_check_sum(txbuf, 7); - - dst_i2c_enable(dst); - dst_reset8820(dst); - retval = write_dst(dst, txbuf, 8); - if (retval < 0) { - dst_i2c_disable(dst); - dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__); - return retval; - } - msleep(3); - retval = read_dst(dst, rxbuf, 1); - dst_i2c_disable(dst); - if (retval < 0) { - dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__); - return retval; - } - if (rxbuf[0] != 0xff) { - dprintk("%s: write reply not 0xff, not ci (%02x)\n", __FUNCTION__, rxbuf[0]); - return retval; - } - if (!dst_wait_dst_ready(dst)) - return 0; - // dst_i2c_enable(i2c); Dimitri - retval = read_dst(dst, rxbuf, 8); - dst_i2c_disable(dst); - if (retval < 0) { - dprintk("%s: read not successful\n", __FUNCTION__); - return retval; - } - if (rxbuf[7] != dst_check_sum(rxbuf, 7)) { - dprintk("%s: checksum failure\n", __FUNCTION__); - return retval; - } - rxbuf[7] = '\0'; - for (i = 0, dsp = &dst_tlist[0]; i < sizeof(dst_tlist) / sizeof(dst_tlist[0]); i++, dsp++) { - if (!strncmp(&rxbuf[dsp->offs], dsp->mstr, strlen(dsp->mstr))) { - use_type_flags = dsp->type_flags; - use_dst_type = dsp->dst_type; - printk("%s: recognize %s\n", __FUNCTION__, dsp->mstr); - break; - } - } - if (i >= sizeof(dst_tlist) / sizeof(dst_tlist[0])) { - printk("%s: unable to recognize %s or %s\n", __FUNCTION__, &rxbuf[0], &rxbuf[1]); - printk("%s please email linux-dvb@linuxtv.org with this type in\n", __FUNCTION__); - use_dst_type = DST_TYPE_IS_SAT; - use_type_flags = DST_TYPE_HAS_SYMDIV; - } - dst_type_print(use_dst_type); - - dst->type_flags = use_type_flags; - dst->dst_type = use_dst_type; - dst_type_flags_print(dst->type_flags); - - if (dst->type_flags & DST_TYPE_HAS_TS204) { - dst_packsize(dst, 204); - } - return 0; -} - -static int dst_command(struct dst_data *dst, u8 * data, u8 len) -{ - int retval; - u8 reply; - - dst_i2c_enable(dst); - dst_reset8820(dst); - retval = write_dst(dst, data, len); - if (retval < 0) { - dst_i2c_disable(dst); - dprintk("%s: write not successful\n", __FUNCTION__); - return retval; - } - msleep(33); - retval = read_dst(dst, &reply, 1); - dst_i2c_disable(dst); - if (retval < 0) { - dprintk("%s: read verify not successful\n", __FUNCTION__); - return retval; - } - if (reply != 0xff) { - dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply); - return 0; - } - if (len >= 2 && data[0] == 0 && (data[1] == 1 || data[1] == 3)) - return 0; - if (!dst_wait_dst_ready(dst)) - return 0; - // dst_i2c_enable(i2c); Per dimitri - retval = read_dst(dst, dst->rxbuffer, 8); - dst_i2c_disable(dst); - if (retval < 0) { - dprintk("%s: read not successful\n", __FUNCTION__); - return 0; - } - if (dst->rxbuffer[7] != dst_check_sum(dst->rxbuffer, 7)) { - dprintk("%s: checksum failure\n", __FUNCTION__); - return 0; - } - return 0; -} - -static int dst_get_signal(struct dst_data *dst) -{ - int retval; - u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb }; - - if ((dst->diseq_flags & ATTEMPT_TUNE) == 0) { - dst->decode_lock = dst->decode_strength = dst->decode_snr = 0; - return 0; - } - if (0 == (dst->diseq_flags & HAS_LOCK)) { - dst->decode_lock = dst->decode_strength = dst->decode_snr = 0; - return 0; - } - if (time_after_eq(jiffies, dst->cur_jiff + (HZ / 5))) { - retval = dst_command(dst, get_signal, 8); - if (retval < 0) - return retval; - if (dst->dst_type == DST_TYPE_IS_SAT) { - dst->decode_lock = ((dst->rxbuffer[6] & 0x10) == 0) ? 1 : 0; - dst->decode_strength = dst->rxbuffer[5] << 8; - dst->decode_snr = dst->rxbuffer[2] << 8 | dst->rxbuffer[3]; - } else if ((dst->dst_type == DST_TYPE_IS_TERR) || (dst->dst_type == DST_TYPE_IS_CABLE)) { - dst->decode_lock = (dst->rxbuffer[1]) ? 1 : 0; - dst->decode_strength = dst->rxbuffer[4] << 8; - dst->decode_snr = dst->rxbuffer[3] << 8; - } - dst->cur_jiff = jiffies; - } - return 0; -} - -/* - * line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00 - * line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00 - * line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00 - * tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00 - * data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00 - * power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00 - * power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 - * Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec - * Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8 - * Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4 - * Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0 - */ - -static int dst_set_diseqc(struct dst_data *dst, u8 * cmd, u8 len) -{ - u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec }; - - if (dst->dst_type == DST_TYPE_IS_TERR) - return 0; - - if (len == 0 || len > 4) - return -EINVAL; - memcpy(&paket[3], cmd, len); - paket[7] = dst_check_sum(&paket[0], 7); - dst_command(dst, paket, 8); - return 0; -} - -static int dst_tone_power_cmd(struct dst_data *dst) -{ - u8 paket[8] = { 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00 }; - - if (dst->dst_type == DST_TYPE_IS_TERR) - return 0; - - if (dst->voltage == SEC_VOLTAGE_OFF) - paket[4] = 0; - else - paket[4] = 1; - if (dst->tone == SEC_TONE_ON) - paket[2] = dst->k22; - else - paket[2] = 0; - paket[7] = dst_check_sum(&paket[0], 7); - dst_command(dst, paket, 8); - return 0; -} - -static int dst_set_voltage(struct dst_data *dst, fe_sec_voltage_t voltage) -{ - u8 *val; - int need_cmd; - - dst->voltage = voltage; - - if (dst->dst_type == DST_TYPE_IS_TERR) - return 0; - - need_cmd = 0; - val = &dst->tx_tuna[0]; - val[8] &= ~0x40; - switch (voltage) { - case SEC_VOLTAGE_13: - if ((dst->diseq_flags & HAS_POWER) == 0) - need_cmd = 1; - dst->diseq_flags |= HAS_POWER; - break; - case SEC_VOLTAGE_18: - if ((dst->diseq_flags & HAS_POWER) == 0) - need_cmd = 1; - dst->diseq_flags |= HAS_POWER; - val[8] |= 0x40; - break; - case SEC_VOLTAGE_OFF: - need_cmd = 1; - dst->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE); - break; - default: - return -EINVAL; - } - if (need_cmd) { - dst_tone_power_cmd(dst); - } - return 0; -} - - -static int dst_set_tone(struct dst_data *dst, fe_sec_tone_mode_t tone) -{ - u8 *val; - - dst->tone = tone; - - if (dst->dst_type == DST_TYPE_IS_TERR) - return 0; - - val = &dst->tx_tuna[0]; - - val[8] &= ~0x1; - - switch (tone) { - case SEC_TONE_OFF: - break; - case SEC_TONE_ON: - val[8] |= 1; - break; - default: - return -EINVAL; - } - dst_tone_power_cmd(dst); - return 0; -} - -static int dst_get_tuna(struct dst_data *dst) -{ - int retval; - if ((dst->diseq_flags & ATTEMPT_TUNE) == 0) - return 0; - dst->diseq_flags &= ~(HAS_LOCK); - if (!dst_wait_dst_ready(dst)) - return 0; - if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) { - /* how to get variable length reply ???? */ - retval = read_dst(dst, dst->rx_tuna, 10); - } else { - retval = read_dst(dst, &dst->rx_tuna[2], 8); - } - if (retval < 0) { - dprintk("%s: read not successful\n", __FUNCTION__); - return 0; - } - if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) { - if (dst->rx_tuna[9] != dst_check_sum(&dst->rx_tuna[0], 9)) { - dprintk("%s: checksum failure?\n", __FUNCTION__); - return 0; - } - } else { - if (dst->rx_tuna[9] != dst_check_sum(&dst->rx_tuna[2], 7)) { - dprintk("%s: checksum failure?\n", __FUNCTION__); - return 0; - } - } - if (dst->rx_tuna[2] == 0 && dst->rx_tuna[3] == 0) - return 0; - dst->decode_freq = ((dst->rx_tuna[2] & 0x7f) << 8) + dst->rx_tuna[3]; - - dst->decode_lock = 1; - /* - dst->decode_n1 = (dst->rx_tuna[4] << 8) + - (dst->rx_tuna[5]); - - dst->decode_n2 = (dst->rx_tuna[8] << 8) + - (dst->rx_tuna[7]); - */ - dst->diseq_flags |= HAS_LOCK; - /* dst->cur_jiff = jiffies; */ - return 1; -} - -static int dst_write_tuna(struct dst_data *dst) -{ - int retval; - u8 reply; - - dprintk("%s: type_flags 0x%x \n", __FUNCTION__, dst->type_flags); - dst->decode_freq = 0; - dst->decode_lock = dst->decode_strength = dst->decode_snr = 0; - if (dst->dst_type == DST_TYPE_IS_SAT) { - if (!(dst->diseq_flags & HAS_POWER)) - dst_set_voltage(dst, SEC_VOLTAGE_13); - } - dst->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE); - dst_i2c_enable(dst); - if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) { - dst_reset8820(dst); - dst->tx_tuna[9] = dst_check_sum(&dst->tx_tuna[0], 9); - retval = write_dst(dst, &dst->tx_tuna[0], 10); - } else { - dst->tx_tuna[9] = dst_check_sum(&dst->tx_tuna[2], 7); - retval = write_dst(dst, &dst->tx_tuna[2], 8); - } - if (retval < 0) { - dst_i2c_disable(dst); - dprintk("%s: write not successful\n", __FUNCTION__); - return retval; - } - msleep(3); - retval = read_dst(dst, &reply, 1); - dst_i2c_disable(dst); - if (retval < 0) { - dprintk("%s: read verify not successful\n", __FUNCTION__); - return retval; - } - if (reply != 0xff) { - dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply); - return 0; - } - dst->diseq_flags |= ATTEMPT_TUNE; - return dst_get_tuna(dst); -} - -static void dst_init(struct dst_data *dst) -{ - static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 }; - static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 }; - static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 }; - dst->inversion = INVERSION_ON; - dst->voltage = SEC_VOLTAGE_13; - dst->tone = SEC_TONE_OFF; - dst->symbol_rate = 29473000; - dst->fec = FEC_AUTO; - dst->diseq_flags = 0; - dst->k22 = 0x02; - dst->bandwidth = BANDWIDTH_7_MHZ; - dst->cur_jiff = jiffies; - if (dst->dst_type == DST_TYPE_IS_SAT) { - dst->frequency = 950000; - memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna)); - } else if (dst->dst_type == DST_TYPE_IS_TERR) { - dst->frequency = 137000000; - memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna)); - } else if (dst->dst_type == DST_TYPE_IS_CABLE) { - dst->frequency = 51000000; - memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna)); - } -} - -struct lkup { - unsigned int cmd; - char *desc; -} looker[] = { - { - FE_GET_INFO, "FE_GET_INFO:"}, { - FE_READ_STATUS, "FE_READ_STATUS:"}, { - FE_READ_BER, "FE_READ_BER:"}, { - FE_READ_SIGNAL_STRENGTH, "FE_READ_SIGNAL_STRENGTH:"}, { - FE_READ_SNR, "FE_READ_SNR:"}, { - FE_READ_UNCORRECTED_BLOCKS, "FE_READ_UNCORRECTED_BLOCKS:"}, { - FE_SET_FRONTEND, "FE_SET_FRONTEND:"}, { - FE_GET_FRONTEND, "FE_GET_FRONTEND:"}, { - FE_SLEEP, "FE_SLEEP:"}, { - FE_INIT, "FE_INIT:"}, { - FE_SET_TONE, "FE_SET_TONE:"}, { -FE_SET_VOLTAGE, "FE_SET_VOLTAGE:"},}; - -static int dst_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct dst_data *dst = fe->data; - int retval; - /* - char *cc; - - cc = "FE_UNSUPP:"; - for(retval = 0; retval < sizeof(looker) / sizeof(looker[0]); retval++) { - if (looker[retval].cmd == cmd) { - cc = looker[retval].desc; - break; - } - } - dprintk("%s cmd %s (0x%x)\n",__FUNCTION__, cc, cmd); - */ - // printk("%s: dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, dst, dst->bt, dst->i2c); - /* should be set by attach, but just in case */ - - switch (cmd) { - case FE_GET_INFO: - { - struct dvb_frontend_info *info; - info = &dst_info_sat; - if (dst->dst_type == DST_TYPE_IS_TERR) - info = &dst_info_terr; - else if (dst->dst_type == DST_TYPE_IS_CABLE) - info = &dst_info_cable; - memcpy(arg, info, sizeof(struct dvb_frontend_info)); - break; - } - case FE_READ_STATUS: - { - fe_status_t *status = arg; - - *status = 0; - if (dst->diseq_flags & HAS_LOCK) { - dst_get_signal(dst); - if (dst->decode_lock) - *status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI; - } - break; - } - - case FE_READ_BER: - { - /* guess */ - // *(u32*) arg = dst->decode_n1; - *(u32 *) arg = 0; - return -EOPNOTSUPP; - } - - case FE_READ_SIGNAL_STRENGTH: - { - dst_get_signal(dst); - *((u16 *) arg) = dst->decode_strength; - break; - } - - case FE_READ_SNR: - { - dst_get_signal(dst); - *((u16 *) arg) = dst->decode_snr; - break; - } - - case FE_READ_UNCORRECTED_BLOCKS: - { - *((u32 *) arg) = 0; /* the stv0299 can't measure BER and */ - return -EOPNOTSUPP; /* errors at the same time.... */ - } - - case FE_SET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - - dst_set_freq(dst, p->frequency); - dst_set_inversion(dst, p->inversion); - if (dst->dst_type == DST_TYPE_IS_SAT) { - dst_set_fec(dst, p->u.qpsk.fec_inner); - dst_set_symbolrate(dst, p->u.qpsk.symbol_rate); - } else if (dst->dst_type == DST_TYPE_IS_TERR) { - dst_set_bandwidth(dst, p->u.ofdm.bandwidth); - } else if (dst->dst_type == DST_TYPE_IS_CABLE) { - dst_set_fec(dst, p->u.qam.fec_inner); - dst_set_symbolrate(dst, p->u.qam.symbol_rate); - } - dst_write_tuna(dst); - - break; - } - - case FE_GET_FRONTEND: - { - struct dvb_frontend_parameters *p = arg; - - - p->frequency = dst->decode_freq; - p->inversion = dst->inversion; - if (dst->dst_type == DST_TYPE_IS_SAT) { - p->u.qpsk.symbol_rate = dst->symbol_rate; - p->u.qpsk.fec_inner = dst_get_fec(dst); - } else if (dst->dst_type == DST_TYPE_IS_TERR) { - p->u.ofdm.bandwidth = dst->bandwidth; - } else if (dst->dst_type == DST_TYPE_IS_CABLE) { - p->u.qam.symbol_rate = dst->symbol_rate; - p->u.qam.fec_inner = dst_get_fec(dst); - p->u.qam.modulation = QAM_AUTO; - } - break; - } - - case FE_SLEEP: - return 0; - - case FE_INIT: - dst_init(dst); - break; - - case FE_DISEQC_SEND_MASTER_CMD: - { - struct dvb_diseqc_master_cmd *cmd = (struct dvb_diseqc_master_cmd *) arg; - retval = dst_set_diseqc(dst, cmd->msg, cmd->msg_len); - if (retval < 0) - return retval; - break; - } - case FE_SET_TONE: - retval = dst_set_tone(dst, (fe_sec_tone_mode_t) arg); - if (retval < 0) - return retval; - break; - case FE_SET_VOLTAGE: - retval = dst_set_voltage(dst, (fe_sec_voltage_t) arg); - if (retval < 0) - return retval; - break; - default: - return -EOPNOTSUPP; - }; - - return 0; -} - -static ssize_t attr_read_type(struct device *dev, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client); - return sprintf(buf, "0x%02x\n", dst->dst_type); -} - -static ssize_t attr_write_type(struct device *dev, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client); - unsigned long type; - type = simple_strtoul(buf, NULL, 0); - dst->dst_type = type & 0xff; - return strlen(buf) + 1; -} - -/* dst_type, "Type of DST card, 0 Satellite, 1 terrestial, 2 Cable, default driver determined"); */ -static struct device_attribute dev_attr_client_type = { - .attr = {.name = "type",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE}, - .show = &attr_read_type, - .store = &attr_write_type, -}; - -static ssize_t attr_read_flags(struct device *dev, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client); - return sprintf(buf, "0x%02x\n", dst->type_flags); -} - -static ssize_t attr_write_flags(struct device *dev, const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct dst_data *dst = (struct dst_data *) i2c_get_clientdata(client); - unsigned long flags; - flags = simple_strtoul(buf, NULL, 0); - dst->type_flags = flags & 0xffffffff; - return strlen(buf) + 1; -} - -/* dst_type_flags, "Type flags of DST card, bitfield 1=10 byte tuner, 2=TS is 204, 4=symdiv"); */ -static struct device_attribute dev_attr_client_flags = { - .attr = {.name = "flags",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE}, - .show = &attr_read_flags, - .store = &attr_write_flags, -}; - -static struct i2c_client client_template; - -static int attach_adapter(struct i2c_adapter *adapter) -{ - struct i2c_client *client; - struct dst_data *dst; - struct bt878 *bt; - struct dvb_frontend_info *info; - int ret; - - bt = bt878_find_by_i2c_adap(adapter); - if (!bt) - return -ENODEV; - - dst = kmalloc(sizeof(struct dst_data), GFP_KERNEL); - if (dst == NULL) { - printk(KERN_INFO "%s: Out of memory.\n", __FUNCTION__); - return -ENOMEM; - } - - memset(dst, 0, sizeof(*dst)); - dst->bt = bt; - dst->i2c = adapter; - if (dst_check_ci(dst) < 0) { - kfree(dst); - return -ENODEV; - } - dst_init(dst); - - dprintk("%s: register dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, (u32) dst, (u32) (dst->bt), (u32) (dst->i2c)); - - switch (dst->dst_type) { - case DST_TYPE_IS_TERR: - info = &dst_info_terr; - break; - case DST_TYPE_IS_CABLE: - info = &dst_info_cable; - break; - case DST_TYPE_IS_SAT: - info = &dst_info_sat; - break; - default: - printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n"); - kfree(dst); - return -ENODEV; - } - - if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) { - kfree(dst); - return -ENOMEM; - } - - memcpy(client, &client_template, sizeof(struct i2c_client)); - client->adapter = adapter; - client->addr = DST_I2C_ADDR; - - i2c_set_clientdata(client, (void *) dst); - - ret = i2c_attach_client(client); - if (ret) { - kfree(client); - kfree(dst); - return -EFAULT; - } - - BUG_ON(!dst->dvb); - - device_create_file(&client->dev, &dev_attr_client_type); - device_create_file(&client->dev, &dev_attr_client_flags); - - ret = dvb_register_frontend(dst_ioctl, dst->dvb, dst, info, THIS_MODULE); - if (ret) { - i2c_detach_client(client); - kfree(client); - kfree(dst); - return -EFAULT; - } - - return 0; -} - -static int detach_client(struct i2c_client *client) -{ - struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client); - - dvb_unregister_frontend(dst_ioctl, state->dvb); - - device_remove_file(&client->dev, &dev_attr_client_type); - device_remove_file(&client->dev, &dev_attr_client_flags); - - i2c_detach_client(client); - BUG_ON(state->dvb); - - kfree(client); - kfree(state); - - return 0; -} - -static int command(struct i2c_client *client, unsigned int cmd, void *arg) -{ - struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client); - - switch (cmd) { - case FE_REGISTER: - state->dvb = (struct dvb_adapter *) arg; - break; - case FE_UNREGISTER: - state->dvb = NULL; - break; - default: - return -EOPNOTSUPP; - } - return 0; -} - -static struct i2c_driver driver = { - .owner = THIS_MODULE, - .name = "dst", - .id = I2C_DRIVERID_DVBFE_DST, - .flags = I2C_DF_NOTIFY, - .attach_adapter = attach_adapter, - .detach_client = detach_client, - .command = command, -}; - -static struct i2c_client client_template = { - I2C_DEVNAME("dst"), - .flags = I2C_CLIENT_ALLOW_USE, - .driver = &driver, -}; - -static int __init init_dst(void) -{ - return i2c_add_driver(&driver); -} - -static void __exit exit_dst(void) -{ - if (i2c_del_driver(&driver)) - printk("dst: driver deregistration failed\n"); -} - -module_init(init_dst); -module_exit(exit_dst); - -MODULE_DESCRIPTION("DST DVB-S Frontend"); -MODULE_AUTHOR("Jamie Honan"); -MODULE_LICENSE("GPL"); diff -puN drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c --- 25/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c~dvb-follow-frontend-changes-in-drivers Thu Nov 18 15:18:02 2004 +++ 25-akpm/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c Thu Nov 18 15:18:02 2004 @@ -24,6 +24,8 @@ #include "dmxdev.h" #include "dvb_demux.h" #include "dvb_net.h" +#include "cx22700.h" +#include "tda1004x.h" #include #include @@ -132,6 +134,8 @@ struct ttusb { #if 0 devfs_handle_t stc_devfs_handle; #endif + + struct dvb_frontend* fe; }; /* ugly workaround ... don't know why it's neccessary to read */ @@ -461,9 +465,10 @@ static int ttusb_init_controller(struct } #ifdef TTUSB_DISEQC -static int ttusb_send_diseqc(struct ttusb *ttusb, +static int ttusb_send_diseqc(struct dvb_frontend* fe, const struct dvb_diseqc_master_cmd *cmd) { + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 b[12] = { 0xaa, ++ttusb->c, 0x18 }; int err; @@ -484,6 +489,7 @@ static int ttusb_send_diseqc(struct ttus } #endif +#if 0 static int ttusb_update_lnb(struct ttusb *ttusb) { u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1, @@ -501,41 +507,25 @@ static int ttusb_update_lnb(struct ttusb return err; } -static int ttusb_set_voltage(struct ttusb *ttusb, fe_sec_voltage_t voltage) +static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) { + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + ttusb->voltage = voltage; return ttusb_update_lnb(ttusb); } #ifdef TTUSB_TONE -static int ttusb_set_tone(struct ttusb *ttusb, fe_sec_tone_mode_t tone) +static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) { + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + ttusb->tone = tone; return ttusb_update_lnb(ttusb); } #endif - -static int ttusb_lnb_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg) -{ - struct ttusb *ttusb = fe->before_after_data; - - switch (cmd) { - case FE_SET_VOLTAGE: - return ttusb_set_voltage(ttusb, (fe_sec_voltage_t) arg); -#ifdef TTUSB_TONE - case FE_SET_TONE: - return ttusb_set_tone(ttusb, (fe_sec_tone_mode_t) arg); -#endif -#ifdef TTUSB_DISEQC - case FE_DISEQC_SEND_MASTER_CMD: - return ttusb_send_diseqc(ttusb, - (struct dvb_diseqc_master_cmd *) - arg); #endif - default: - return -EOPNOTSUPP; - }; -} + #if 0 static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq) @@ -560,7 +550,7 @@ static void ttusb_handle_sec_data(struct const u8 * data, int len); #endif -int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid; +static int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid; static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack, int len) @@ -1071,38 +1061,183 @@ static struct file_operations stc_fops = }; #endif -u32 functionality(struct i2c_adapter *adapter) +static u32 functionality(struct i2c_adapter *adapter) { return I2C_FUNC_I2C; } -static struct i2c_algorithm ttusb_dec_algo = { - .name = "ttusb dec i2c algorithm", - .id = I2C_ALGO_BIT, - .master_xfer = master_xfer, - .functionality = functionality, -}; -static int client_register(struct i2c_client *client) + +static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { - struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter); + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 data[4]; + struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) }; + u32 div; + + div = (params->frequency + 36166667) / 166667; - if (client->driver->command) - return client->driver->command(client, FE_REGISTER, ttusb->adapter); + data[0] = (div >> 8) & 0x7f; + data[1] = div & 0xff; + data[2] = ((div >> 10) & 0x60) | 0x85; + data[3] = params->frequency < 592000000 ? 0x40 : 0x80; + if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } -static int client_unregister(struct i2c_client *client) +struct cx22700_config alps_tdmb7_config = { + .demod_address = 0x43, + .pll_set = alps_tdmb7_pll_set, +}; + + + + + +static int philips_tdm1316l_pll_init(struct dvb_frontend* fe) { - struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter); + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; + static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 }; + struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) }; + + // setup PLL configuration + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO; + msleep(1); + + // disable the mc44BC374c (do not check for errors) + tuner_msg.addr = 0x65; + tuner_msg.buf = disable_mc44BC374c; + tuner_msg.len = sizeof(disable_mc44BC374c); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { + i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1); + } - if (client->driver->command) - return client->driver->command(client, FE_UNREGISTER, ttusb->adapter); + return 0; +} + +static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + u8 tuner_buf[4]; + struct i2c_msg tuner_msg = {.addr=0x60, .flags=0, .buf=tuner_buf, .len=sizeof(tuner_buf) }; + int tuner_frequency = 0; + u8 band, cp, filter; + + // determine charge pump + tuner_frequency = params->frequency + 36130000; + if (tuner_frequency < 87000000) return -EINVAL; + else if (tuner_frequency < 130000000) cp = 3; + else if (tuner_frequency < 160000000) cp = 5; + else if (tuner_frequency < 200000000) cp = 6; + else if (tuner_frequency < 290000000) cp = 3; + else if (tuner_frequency < 420000000) cp = 5; + else if (tuner_frequency < 480000000) cp = 6; + else if (tuner_frequency < 620000000) cp = 3; + else if (tuner_frequency < 830000000) cp = 5; + else if (tuner_frequency < 895000000) cp = 7; + else return -EINVAL; + + // determine band + if (params->frequency < 49000000) return -EINVAL; + else if (params->frequency < 159000000) band = 1; + else if (params->frequency < 444000000) band = 2; + else if (params->frequency < 861000000) band = 4; + else return -EINVAL; + + // setup PLL filter + switch (params->u.ofdm.bandwidth) { + case BANDWIDTH_6_MHZ: + tda1004x_write_byte(fe, 0x0C, 0); + filter = 0; + break; + + case BANDWIDTH_7_MHZ: + tda1004x_write_byte(fe, 0x0C, 0); + filter = 0; + break; + + case BANDWIDTH_8_MHZ: + tda1004x_write_byte(fe, 0x0C, 0xFF); + filter = 1; + break; + default: + return -EINVAL; + } + + // calculate divisor + // ((36130000+((1000000/6)/2)) + Finput)/(1000000/6) + tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000; + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xca; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO; + + msleep(1); return 0; } +static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) +{ + struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; + + return request_firmware(fw, name, &ttusb->dev->dev); +} + +struct tda1004x_config philips_tdm1316l_config = { + + .demod_address = 0x8, + .invert = 1, + .pll_init = philips_tdm1316l_pll_init, + .pll_set = philips_tdm1316l_pll_set, + .request_firmware = philips_tdm1316l_request_firmware, +}; + + + +static void frontend_init(struct ttusb* ttusb) +{ + switch(ttusb->dev->descriptor.idProduct) { + case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??)) + // try the ALPS TDMB7 first + ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) break; + + // Philips td1316 + ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) break; + break; + } + + if (ttusb->fe == NULL) { + printk("dvb-ttusb-budget: A frontend driver was not found for device %04x/%04x\n", + ttusb->dev->descriptor.idVendor, + ttusb->dev->descriptor.idProduct); + } else { + if (dvb_register_frontend(ttusb->adapter, ttusb->fe)) { + printk("dvb-ttusb-budget: Frontend registration failed!\n"); + if (ttusb->fe->ops->release) + ttusb->fe->ops->release(ttusb->fe); + ttusb->fe = NULL; + } + } +} + + + +static struct i2c_algorithm ttusb_dec_algo = { + .name = "ttusb dec i2c algorithm", + .id = I2C_ALGO_BIT, + .master_xfer = master_xfer, + .functionality = functionality, +}; + static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct usb_device *udev; @@ -1140,6 +1275,7 @@ static int ttusb_probe(struct usb_interf up(&ttusb->sem); dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE); + ttusb->adapter->priv = ttusb; /* i2c */ memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter)); @@ -1155,8 +1291,6 @@ static int ttusb_probe(struct usb_interf ttusb->i2c_adap.algo = &ttusb_dec_algo; ttusb->i2c_adap.algo_data = NULL; ttusb->i2c_adap.id = I2C_ALGO_BIT; - ttusb->i2c_adap.client_register = client_register; - ttusb->i2c_adap.client_unregister = client_unregister; result = i2c_add_adapter(&ttusb->i2c_adap); if (result) { @@ -1164,9 +1298,6 @@ static int ttusb_probe(struct usb_interf return result; } - dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL, - ttusb); - memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux)); ttusb->dvb_demux.dmx.capabilities = @@ -1218,9 +1349,10 @@ static int ttusb_probe(struct usb_interf S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH, &stc_fops, ttusb); #endif - usb_set_intfdata(intf, (void *) ttusb); + frontend_init(ttusb); + return 0; } @@ -1238,7 +1370,7 @@ static void ttusb_disconnect(struct usb_ dvb_net_release(&ttusb->dvbnet); dvb_dmxdev_release(&ttusb->dmxdev); dvb_dmx_release(&ttusb->dvb_demux); - + if (ttusb->fe != NULL) dvb_unregister_frontend(ttusb->fe); i2c_del_adapter(&ttusb->i2c_adap); dvb_unregister_adapter(ttusb->adapter); @@ -1250,8 +1382,8 @@ static void ttusb_disconnect(struct usb_ } static struct usb_device_id ttusb_table[] = { - {USB_DEVICE(0xb48, 0x1003)}, - {USB_DEVICE(0xb48, 0x1004)}, /* to be confirmed ???? */ +/* {USB_DEVICE(0xb48, 0x1003)},UNDEFINED HARDWARE - mail linuxtv.org list */ +/* {USB_DEVICE(0xb48, 0x1004)},UNDEFINED HARDWARE - mail linuxtv.org list*/ /* to be confirmed ???? */ {USB_DEVICE(0xb48, 0x1005)}, {} }; diff -puN drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h --- 25/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h~dvb-follow-frontend-changes-in-drivers Thu Nov 18 15:18:02 2004 +++ 25-akpm/drivers/media/dvb/ttusb-budget/dvb-ttusb-dspbootcode.h Thu Nov 18 15:18:02 2004 @@ -1,7 +1,7 @@ #include -u8 dsp_bootcode [] = { +static u8 dsp_bootcode [] = { 0x08, 0xaa, 0x00, 0x18, 0x00, 0x03, 0x08, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 0x80, 0x18, 0x5f, 0x00, 0x00, 0x01, 0x80, 0x77, 0x18, 0x2a, 0xeb, diff -puN drivers/media/dvb/ttusb-dec/ttusb_dec.c~dvb-follow-frontend-changes-in-drivers drivers/media/dvb/ttusb-dec/ttusb_dec.c --- 25/drivers/media/dvb/ttusb-dec/ttusb_dec.c~dvb-follow-frontend-changes-in-drivers Thu Nov 18 15:18:02 2004 +++ 25-akpm/drivers/media/dvb/ttusb-dec/ttusb_dec.c Thu Nov 18 15:18:02 2004 @@ -30,11 +30,7 @@ #include #include #include -#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE) #include -#else -#warning "CRC checking of firmware not available" -#endif #include #include "dmxdev.h" @@ -42,6 +38,7 @@ #include "dvb_filter.h" #include "dvb_frontend.h" #include "dvb_net.h" +#include "ttusbdecfe.h" static int debug; static int output_pva; @@ -69,9 +66,6 @@ MODULE_PARM_DESC(output_pva, "Output PVA #define MAX_PVA_LENGTH 6144 -#define LOF_HI 10600000 -#define LOF_LO 9750000 - enum ttusb_dec_model { TTUSB_DEC2000T, TTUSB_DEC2540T, @@ -102,12 +96,9 @@ struct ttusb_dec { struct dvb_demux demux; struct dmx_frontend frontend; struct dvb_net dvb_net; - struct dvb_frontend_info *frontend_info; - int (*frontend_ioctl) (struct dvb_frontend *, unsigned int, void *); + struct dvb_frontend* fe; u16 pid[DMX_PES_OTHER]; - int hi_band; - int voltage; /* USB bits */ struct usb_device *udev; @@ -166,32 +157,6 @@ struct filter_info { struct list_head filter_info_list; }; -static struct dvb_frontend_info dec2000t_frontend_info = { - .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", - .type = FE_OFDM, - .frequency_min = 51000000, - .frequency_max = 858000000, - .frequency_stepsize = 62500, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, -}; - -static struct dvb_frontend_info dec3000s_frontend_info = { - .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", - .type = FE_QPSK, - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 125, - .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | - FE_CAN_HIERARCHY_AUTO, -}; - static void ttusb_dec_set_model(struct ttusb_dec *dec, enum ttusb_dec_model model); @@ -1170,10 +1135,9 @@ static int ttusb_dec_boot_dsp(struct ttu u16 firmware_csum = 0; u16 firmware_csum_ns; u32 firmware_size_nl; -#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE) u32 crc32_csum, crc32_check, tmp; -#endif const struct firmware *fw_entry = NULL; + dprintk("%s\n", __FUNCTION__); if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) { @@ -1194,7 +1158,6 @@ static int ttusb_dec_boot_dsp(struct ttu /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored at offset 56 of file, so use it to check if the firmware file is valid. */ -#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE) crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; memcpy(&tmp, &firmware[56], 4); crc32_check = htonl(tmp); @@ -1204,7 +1167,6 @@ static int ttusb_dec_boot_dsp(struct ttu __FUNCTION__, crc32_csum, crc32_check); return -1; } -#endif memcpy(idstring, &firmware[36], 20); idstring[20] = '\0'; printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); @@ -1404,6 +1366,7 @@ static void ttusb_dec_exit_dvb(struct tt dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend); dvb_dmxdev_release(&dec->dmxdev); dvb_dmx_release(&dec->demux); + if (dec->fe) dvb_unregister_frontend(dec->fe); dvb_unregister_adapter(dec->adapter); } @@ -1435,264 +1398,6 @@ static void ttusb_dec_exit_tasklet(struc } } -static int ttusb_dec_2000t_frontend_ioctl(struct dvb_frontend *fe, unsigned int cmd, - void *arg) -{ - struct ttusb_dec *dec = fe->data; - - dprintk("%s\n", __FUNCTION__); - - switch (cmd) { - - case FE_GET_INFO: - dprintk("%s: FE_GET_INFO\n", __FUNCTION__); - memcpy(arg, dec->frontend_info, - sizeof (struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: { - fe_status_t *status = (fe_status_t *)arg; - dprintk("%s: FE_READ_STATUS\n", __FUNCTION__); - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; - break; - } - - case FE_READ_BER: { - u32 *ber = (u32 *)arg; - dprintk("%s: FE_READ_BER\n", __FUNCTION__); - *ber = 0; - return -ENOSYS; - break; - } - - case FE_READ_SIGNAL_STRENGTH: { - dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__); - *(s32 *)arg = 0xFF; - return -ENOSYS; - break; - } - - case FE_READ_SNR: - dprintk("%s: FE_READ_SNR\n", __FUNCTION__); - *(s32 *)arg = 0; - return -ENOSYS; - break; - - case FE_READ_UNCORRECTED_BLOCKS: - dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__); - *(u32 *)arg = 0; - return -ENOSYS; - break; - - case FE_SET_FRONTEND: { - struct dvb_frontend_parameters *p = - (struct dvb_frontend_parameters *)arg; - u8 b[] = { 0x00, 0x00, 0x00, 0x03, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0xff, - 0x00, 0x00, 0x00, 0xff }; - u32 freq; - - dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__); - - dprintk(" frequency->%d\n", p->frequency); - dprintk(" symbol_rate->%d\n", - p->u.qam.symbol_rate); - dprintk(" inversion->%d\n", p->inversion); - - freq = htonl(p->frequency / 1000); - memcpy(&b[4], &freq, sizeof (u32)); - ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL); - - break; - } - - case FE_GET_FRONTEND: - dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__); - break; - - case FE_SLEEP: - dprintk("%s: FE_SLEEP\n", __FUNCTION__); - return -ENOSYS; - break; - - case FE_INIT: - dprintk("%s: FE_INIT\n", __FUNCTION__); - break; - - default: - dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd); - return -EINVAL; - - } - - return 0; -} - -static int ttusb_dec_3000s_frontend_ioctl(struct dvb_frontend *fe, - unsigned int cmd, void *arg) -{ - struct ttusb_dec *dec = fe->data; - - dprintk("%s\n", __FUNCTION__); - - switch (cmd) { - - case FE_GET_INFO: - dprintk("%s: FE_GET_INFO\n", __FUNCTION__); - memcpy(arg, dec->frontend_info, - sizeof (struct dvb_frontend_info)); - break; - - case FE_READ_STATUS: { - fe_status_t *status = (fe_status_t *)arg; - dprintk("%s: FE_READ_STATUS\n", __FUNCTION__); - *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | - FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; - break; - } - - case FE_READ_BER: { - u32 *ber = (u32 *)arg; - dprintk("%s: FE_READ_BER\n", __FUNCTION__); - *ber = 0; - return -ENOSYS; - break; - } - - case FE_READ_SIGNAL_STRENGTH: { - dprintk("%s: FE_READ_SIGNAL_STRENGTH\n", __FUNCTION__); - *(s32 *)arg = 0xFF; - return -ENOSYS; - break; - } - - case FE_READ_SNR: - dprintk("%s: FE_READ_SNR\n", __FUNCTION__); - *(s32 *)arg = 0; - return -ENOSYS; - break; - - case FE_READ_UNCORRECTED_BLOCKS: - dprintk("%s: FE_READ_UNCORRECTED_BLOCKS\n", __FUNCTION__); - *(u32 *)arg = 0; - return -ENOSYS; - break; - - case FE_SET_FRONTEND: { - struct dvb_frontend_parameters *p = - (struct dvb_frontend_parameters *)arg; - u8 b[] = { 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x01, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00 }; - u32 freq; - u32 sym_rate; - u32 band; - u32 lnb_voltage; - - dprintk("%s: FE_SET_FRONTEND\n", __FUNCTION__); - - dprintk(" frequency->%d\n", p->frequency); - dprintk(" symbol_rate->%d\n", - p->u.qam.symbol_rate); - dprintk(" inversion->%d\n", p->inversion); - - freq = htonl(p->frequency + - (dec->hi_band ? LOF_HI : LOF_LO)); - memcpy(&b[4], &freq, sizeof(u32)); - sym_rate = htonl(p->u.qam.symbol_rate); - memcpy(&b[12], &sym_rate, sizeof(u32)); - band = htonl(dec->hi_band ? LOF_HI : LOF_LO); - memcpy(&b[24], &band, sizeof(u32)); - lnb_voltage = htonl(dec->voltage); - memcpy(&b[28], &lnb_voltage, sizeof(u32)); - - ttusb_dec_send_command(dec, 0x71, sizeof(b), b, NULL, NULL); - - break; - } - - case FE_GET_FRONTEND: - dprintk("%s: FE_GET_FRONTEND\n", __FUNCTION__); - break; - - case FE_SLEEP: - dprintk("%s: FE_SLEEP\n", __FUNCTION__); - return -ENOSYS; - break; - - case FE_INIT: - dprintk("%s: FE_INIT\n", __FUNCTION__); - break; - - case FE_DISEQC_SEND_MASTER_CMD: { - u8 b[] = { 0x00, 0xff, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 }; - struct dvb_diseqc_master_cmd *cmd = arg; - memcpy(&b[4], cmd->msg, cmd->msg_len); - dprintk("%s: FE_DISEQC_SEND_MASTER_CMD\n", __FUNCTION__); - ttusb_dec_send_command(dec, 0x72, - sizeof(b) - (6 - cmd->msg_len), b, - NULL, NULL); - break; - } - - case FE_DISEQC_SEND_BURST: - dprintk("%s: FE_DISEQC_SEND_BURST\n", __FUNCTION__); - break; - - case FE_SET_TONE: { - fe_sec_tone_mode_t tone = (fe_sec_tone_mode_t)arg; - dprintk("%s: FE_SET_TONE\n", __FUNCTION__); - dec->hi_band = (SEC_TONE_ON == tone); - break; - } - - case FE_SET_VOLTAGE: - dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__); - switch ((fe_sec_voltage_t) arg) { - case SEC_VOLTAGE_13: - dec->voltage = 13; - break; - case SEC_VOLTAGE_18: - dec->voltage = 18; - break; - default: - return -EINVAL; - break; - } - break; - - default: - dprintk("%s: unknown IOCTL (0x%X)\n", __FUNCTION__, cmd); - return -EINVAL; - - } - - return 0; -} - -static void ttusb_dec_init_frontend(struct ttusb_dec *dec) -{ - int ret; - ret = dvb_register_frontend(dec->frontend_ioctl, dec->adapter, dec, dec->frontend_info, THIS_MODULE); -} - -static void ttusb_dec_exit_frontend(struct ttusb_dec *dec) -{ - dvb_unregister_frontend(dec->frontend_ioctl, dec->adapter); -} - static void ttusb_dec_init_filters(struct ttusb_dec *dec) { INIT_LIST_HEAD(&dec->filter_info_list); @@ -1711,6 +1416,18 @@ static void ttusb_dec_exit_filters(struc } } +int fe_send_command(struct dvb_frontend* fe, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]) +{ + struct ttusb_dec* dec = (struct ttusb_dec*) fe->dvb->priv; + return ttusb_dec_send_command(dec, command, param_length, params, result_length, cmd_result); +} + +struct ttusbdecfe_config fe_config = { + .send_command = fe_send_command +}; + static int ttusb_dec_probe(struct usb_interface *intf, const struct usb_device_id *id) { @@ -1752,7 +1469,32 @@ static int ttusb_dec_probe(struct usb_in return 0; } ttusb_dec_init_dvb(dec); - ttusb_dec_init_frontend(dec); + + dec->adapter->priv = dec; + switch (id->idProduct) { + case 0x1006: + dec->fe = ttusbdecfe_dvbs_attach(&fe_config); + break; + + case 0x1008: + case 0x1009: + dec->fe = ttusbdecfe_dvbt_attach(&fe_config); + break; + } + + if (dec->fe == NULL) { + printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n", + dec->udev->descriptor.idVendor, + dec->udev->descriptor.idProduct); + } else { + if (dvb_register_frontend(dec->adapter, dec->fe)) { + printk("budget-ci: Frontend registration failed!\n"); + if (dec->fe->ops->release) + dec->fe->ops->release(dec->fe); + dec->fe = NULL; + } + } + ttusb_dec_init_v_pes(dec); ttusb_dec_init_filters(dec); ttusb_dec_init_tasklet(dec); @@ -1776,7 +1518,6 @@ static void ttusb_dec_disconnect(struct ttusb_dec_exit_tasklet(dec); ttusb_dec_exit_filters(dec); ttusb_dec_exit_usb(dec); - ttusb_dec_exit_frontend(dec); ttusb_dec_exit_dvb(dec); } @@ -1792,22 +1533,16 @@ static void ttusb_dec_set_model(struct t case TTUSB_DEC2000T: dec->model_name = "DEC2000-t"; dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; - dec->frontend_info = &dec2000t_frontend_info; - dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl; break; case TTUSB_DEC2540T: dec->model_name = "DEC2540-t"; dec->firmware_name = "dvb-ttusb-dec-2540t.fw"; - dec->frontend_info = &dec2000t_frontend_info; - dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl; break; case TTUSB_DEC3000S: dec->model_name = "DEC3000-s"; dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; - dec->frontend_info = &dec3000s_frontend_info; - dec->frontend_ioctl = ttusb_dec_3000s_frontend_ioctl; break; } } diff -puN /dev/null drivers/media/dvb/ttusb-dec/ttusbdecfe.c --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/drivers/media/dvb/ttusb-dec/ttusbdecfe.c Thu Nov 18 15:18:02 2004 @@ -0,0 +1,255 @@ +/* + * TTUSB DEC Frontend Driver + * + * Copyright (C) 2003-2004 Alex Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include "dvb_frontend.h" +#include "ttusbdecfe.h" + + +#define LOF_HI 10600000 +#define LOF_LO 9750000 + +struct ttusbdecfe_state { + + struct dvb_frontend_ops ops; + + /* configuration settings */ + const struct ttusbdecfe_config* config; + + struct dvb_frontend frontend; + + u8 hi_band; + u8 voltage; +}; + + +static int ttusbdecfe_read_status(struct dvb_frontend* fe, fe_status_t* status) +{ + *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | + FE_HAS_SYNC | FE_HAS_CARRIER | FE_HAS_LOCK; + + return 0; +} + +static int ttusbdecfe_dvbt_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + u8 b[] = { 0x00, 0x00, 0x00, 0x03, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0xff, + 0x00, 0x00, 0x00, 0xff }; + + u32 freq = htonl(p->frequency / 1000); + memcpy(&b[4], &freq, sizeof (u32)); + state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); + + return 0; +} + +static int ttusbdecfe_dvbs_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + u8 b[] = { 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x01, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00 }; + u32 freq; + u32 sym_rate; + u32 band; + u32 lnb_voltage; + + freq = htonl(p->frequency + + (state->hi_band ? LOF_HI : LOF_LO)); + memcpy(&b[4], &freq, sizeof(u32)); + sym_rate = htonl(p->u.qam.symbol_rate); + memcpy(&b[12], &sym_rate, sizeof(u32)); + band = htonl(state->hi_band ? LOF_HI : LOF_LO); + memcpy(&b[24], &band, sizeof(u32)); + lnb_voltage = htonl(state->voltage); + memcpy(&b[28], &lnb_voltage, sizeof(u32)); + + state->config->send_command(fe, 0x71, sizeof(b), b, NULL, NULL); + + return 0; +} + +static int ttusbdecfe_dvbs_diseqc_send_master_cmd(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + u8 b[] = { 0x00, 0xff, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00 }; + + memcpy(&b[4], cmd->msg, cmd->msg_len); + + state->config->send_command(fe, 0x72, + sizeof(b) - (6 - cmd->msg_len), b, + NULL, NULL); + + return 0; +} + + +static int ttusbdecfe_dvbs_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + state->hi_band = (SEC_TONE_ON == tone); + + return 0; +} + + +static int ttusbdecfe_dvbs_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + + switch (voltage) { + case SEC_VOLTAGE_13: + state->voltage = 13; + break; + case SEC_VOLTAGE_18: + state->voltage = 18; + break; + default: + return -EINVAL; + } + + return 0; +} + +static void ttusbdecfe_release(struct dvb_frontend* fe) +{ + struct ttusbdecfe_state* state = (struct ttusbdecfe_state*) fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops ttusbdecfe_dvbt_ops; + +struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config) +{ + struct ttusbdecfe_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + memcpy(&state->ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops)); + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops ttusbdecfe_dvbs_ops; + +struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config) +{ + struct ttusbdecfe_state* state = NULL; + + /* allocate memory for the internal state */ + state = (struct ttusbdecfe_state*) kmalloc(sizeof(struct ttusbdecfe_state), GFP_KERNEL); + if (state == NULL) goto error; + + /* setup the state */ + state->config = config; + state->voltage = 0; + state->hi_band = 0; + memcpy(&state->ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops)); + + /* create dvb_frontend */ + state->frontend.ops = &state->ops; + state->frontend.demodulator_priv = state; + return &state->frontend; + +error: + if (state) kfree(state); + return NULL; +} + +static struct dvb_frontend_ops ttusbdecfe_dvbt_ops = { + + .info = { + .name = "TechnoTrend/Hauppauge DEC2000-t Frontend", + .type = FE_OFDM, + .frequency_min = 51000000, + .frequency_max = 858000000, + .frequency_stepsize = 62500, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = ttusbdecfe_release, + + .set_frontend = ttusbdecfe_dvbt_set_frontend, + + .read_status = ttusbdecfe_read_status, +}; + +static struct dvb_frontend_ops ttusbdecfe_dvbs_ops = { + + .info = { + .name = "TechnoTrend/Hauppauge DEC3000-s Frontend", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 125, + .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | + FE_CAN_HIERARCHY_AUTO, + }, + + .release = ttusbdecfe_release, + + .set_frontend = ttusbdecfe_dvbs_set_frontend, + + .read_status = ttusbdecfe_read_status, + + .diseqc_send_master_cmd = ttusbdecfe_dvbs_diseqc_send_master_cmd, + .set_voltage = ttusbdecfe_dvbs_set_voltage, + .set_tone = ttusbdecfe_dvbs_set_tone, +}; + +MODULE_DESCRIPTION("TTUSB DEC DVB-T/S Demodulator driver"); +MODULE_AUTHOR("Alex Woods/Andrew de Quincey"); +MODULE_LICENSE("GPL"); + +EXPORT_SYMBOL(ttusbdecfe_dvbt_attach); +EXPORT_SYMBOL(ttusbdecfe_dvbs_attach); diff -puN /dev/null drivers/media/dvb/ttusb-dec/ttusbdecfe.h --- /dev/null Thu Apr 11 07:25:15 2002 +++ 25-akpm/drivers/media/dvb/ttusb-dec/ttusbdecfe.h Thu Nov 18 15:18:02 2004 @@ -0,0 +1,38 @@ +/* + * TTUSB DEC Driver + * + * Copyright (C) 2003-2004 Alex Woods + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef TTUSBDECFE_H +#define TTUSBDECFE_H + +#include + +struct ttusbdecfe_config +{ + int (*send_command)(struct dvb_frontend* fe, const u8 command, + int param_length, const u8 params[], + int *result_length, u8 cmd_result[]); +}; + +extern struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* config); + +extern struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* config); + +#endif // TTUSBDECFE_H _