diff options
author | Dave Jones <davej@redhat.com> | 2006-06-29 16:01:54 -0400 |
---|---|---|
committer | Dave Jones <davej@redhat.com> | 2006-06-29 16:01:54 -0400 |
commit | 55b4d6a52195a8f277ffddf755ddaff359878f41 (patch) | |
tree | 06a3183a562f8da4688f65023f7a18dcad702956 /drivers/media/dvb | |
parent | adf8a287150667feb5747f8beade62acacc17d4e (diff) | |
parent | 1f1332f727c3229eb2166a83fec5d3de6a73dce2 (diff) |
Merge ../linus
Conflicts:
drivers/char/agp/Kconfig
Diffstat (limited to 'drivers/media/dvb')
117 files changed, 3842 insertions, 1573 deletions
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c index 9c7f122826e..3be87c72e37 100644 --- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c +++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c @@ -14,6 +14,7 @@ #include "stv0297.h" #include "mt312.h" #include "lgdt330x.h" +#include "lg_h06xf.h" #include "dvb-pll.h" /* lnb control */ @@ -166,11 +167,12 @@ static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend* fe, u32 srate, return 0; } -static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) +static int samsung_tbmu24112_tuner_set_params(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 flexcop_device *fc = fe->dvb->priv; div = params->frequency / 125; @@ -181,8 +183,11 @@ static int samsung_tbmu24112_pll_set(struct dvb_frontend* fe, struct i2c_adapter if (params->frequency < 1500000) buf[3] |= 0x10; - if (i2c_transfer(i2c, &msg, 1) != 1) + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) { return -EIO; + } return 0; } @@ -241,7 +246,6 @@ static struct stv0299_config samsung_tbmu24112_config = { .volt13_op0_op1 = STV0299_VOLT13_OP1, .min_delay_ms = 100, .set_symbol_rate = samsung_tbmu24112_set_symbol_rate, - .pll_set = samsung_tbmu24112_pll_set, }; /* dvb-t mt352 */ @@ -264,11 +268,14 @@ static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) return 0; } -static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +static int samsung_tdtc9251dh0_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters *params, u8* pllbuf, int buf_len) { u32 div; unsigned char bs = 0; + if (buf_len < 5) + return -EINVAL; + #define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */ div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; @@ -276,19 +283,18 @@ static int samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_front 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[0] = 0x61; pllbuf[1] = div >> 8; pllbuf[2] = div & 0xff; pllbuf[3] = 0xcc; pllbuf[4] = bs; - return 0; + return 5; } static struct mt352_config samsung_tdtc9251dh0_config = { .demod_address = 0x0f, .demod_init = samsung_tdtc9251dh0_demod_init, - .pll_set = samsung_tdtc9251dh0_pll_set, }; static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name) @@ -297,56 +303,21 @@ static int flexcop_fe_request_firmware(struct dvb_frontend* fe, const struct fir return request_firmware(fw, name, fc->dev); } -static int lgdt3303_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) +static int lgdt3303_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) { struct flexcop_device *fc = fe->dvb->priv; - u8 buf[4]; - struct i2c_msg msg = - { .addr = 0x61, .flags = 0, .buf = buf, .len = 4 }; - int err; - - dvb_pll_configure(&dvb_pll_tdvs_tua6034,buf, params->frequency, 0); - dprintk(1, "%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n", - __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]); - if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt3303: %s error " - "(addr %02x <- %02x, err = %i)\n", - __FUNCTION__, buf[0], buf[1], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } - - buf[0] = 0x86 | 0x18; - buf[1] = 0x50; - msg.len = 2; - if ((err = i2c_transfer(&fc->i2c_adap, &msg, 1)) != 1) { - printk(KERN_WARNING "lgdt3303: %s error " - "(addr %02x <- %02x, err = %i)\n", - __FUNCTION__, buf[0], buf[1], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } - - return 0; + return lg_h06xf_pll_set(fe, &fc->i2c_adap, params); } static struct lgdt330x_config air2pc_atsc_hd5000_config = { .demod_address = 0x59, .demod_chip = LGDT3303, .serial_mpeg = 0x04, - .pll_set = lgdt3303_pll_set, .clock_polarity_flip = 1, }; static struct nxt200x_config samsung_tbmv_config = { .demod_address = 0x0a, - .pll_address = 0xc2, - .pll_desc = &dvb_pll_samsung_tbmv, }; static struct bcm3510_config air2pc_atsc_first_gen_config = { @@ -354,7 +325,7 @@ static struct bcm3510_config air2pc_atsc_first_gen_config = { .request_firmware = flexcop_fe_request_firmware, }; -static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) { u8 buf[4]; u32 div; @@ -371,6 +342,8 @@ static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct d if (params->frequency < 1550000) buf[3] |= 0x02; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) return -EIO; return 0; @@ -379,9 +352,52 @@ static int skystar23_samsung_tbdu18132_pll_set(struct dvb_frontend* fe, struct d static struct mt312_config skystar23_samsung_tbdu18132_config = { .demod_address = 0x0e, - .pll_set = skystar23_samsung_tbdu18132_pll_set, }; +static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct flexcop_device *fc = fe->dvb->priv; + u8 buf[4]; + u16 div; + int ret; + +/* 62.5 kHz * 10 */ +#define REF_FREQ 625 +#define FREQ_OFFSET 36125 + + div = ((fep->frequency/1000 + FREQ_OFFSET ) * 10) / REF_FREQ; // 4 MHz = 4000 KHz + + buf[0] = (u8)( div >> 8) & 0x7f; + buf[1] = (u8) div & 0xff; + +/* F(osc) = N * Reference Freq. (62.5 kHz) + * byte 2 : 0 N14 N13 N12 N11 N10 N9 N8 + * byte 3 : N7 N6 N5 N4 N3 N2 N1 N0 + * byte 4 : 1 * * AGD R3 R2 R1 R0 + * byte 5 : C1 * RE RTS BS4 BS3 BS2 BS1 + * AGD = 1, R3 R2 R1 R0 = 0 1 0 1 => byte 4 = 1**10101 = 0x95 */ + buf[2] = 0x95; + +// Range(MHz) C1 * RE RTS BS4 BS3 BS2 BS1 Byte 5 +// 47 - 153 0 * 0 0 0 0 0 1 0x01 +// 153 - 430 0 * 0 0 0 0 1 0 0x02 +// 430 - 822 0 * 0 0 1 0 0 0 0x08 +// 822 - 862 1 * 0 0 1 0 0 0 0x88 + + if (fep->frequency <= 153000000) buf[3] = 0x01; + else if (fep->frequency <= 430000000) buf[3] = 0x02; + else if (fep->frequency <= 822000000) buf[3] = 0x08; + else buf[3] = 0x88; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]); + ret = fc->i2c_request(fc,FC_WRITE,FC_I2C_PORT_TUNER,0x61,buf[0],&buf[1],3); + deb_tuner("tuner write returned: %d\n",ret); + + return 0; +} static u8 alps_tdee4_stv0297_inittab[] = { 0x80, 0x01, @@ -490,7 +506,9 @@ int flexcop_frontend_init(struct flexcop_device *fc) /* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */ if ((fc->fe = stv0299_attach(&samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) { - ops = fc->fe->ops; + ops = &fc->fe->ops; + + ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params; ops->set_voltage = flexcop_set_voltage; @@ -503,16 +521,19 @@ int flexcop_frontend_init(struct flexcop_device *fc) /* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */ if ((fc->fe = mt352_attach(&samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) { fc->dev_type = FC_AIR_DVB; + fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs; info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address); } else /* try the air atsc 2nd generation (nxt2002) */ if ((fc->fe = nxt200x_attach(&samsung_tbmv_config, &fc->i2c_adap)) != NULL) { fc->dev_type = FC_AIR_ATSC2; + dvb_pll_attach(fc->fe, 0x61, &fc->i2c_adap, &dvb_pll_samsung_tbmv); info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address); } else /* try the air atsc 3nd generation (lgdt3303) */ if ((fc->fe = lgdt330x_attach(&air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) { fc->dev_type = FC_AIR_ATSC3; + fc->fe->ops.tuner_ops.set_params = lgdt3303_tuner_set_params; info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address); } else /* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */ @@ -523,11 +544,14 @@ int flexcop_frontend_init(struct flexcop_device *fc) /* try the cable dvb (stv0297) */ if ((fc->fe = stv0297_attach(&alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) { fc->dev_type = FC_CABLE; + fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params; info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address); } else /* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */ if ((fc->fe = vp310_mt312_attach(&skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) { - ops = fc->fe->ops; + ops = &fc->fe->ops; + + ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params; ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd; ops->diseqc_send_burst = flexcop_diseqc_send_burst; @@ -547,7 +571,7 @@ int flexcop_frontend_init(struct flexcop_device *fc) } else { if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) { err("frontend registration failed!"); - ops = fc->fe->ops; + ops = &fc->fe->ops; if (ops->release != NULL) ops->release(fc->fe); fc->fe = NULL; diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c index 9bc40bdcc28..f0404170219 100644 --- a/drivers/media/dvb/b2c2/flexcop-pci.c +++ b/drivers/media/dvb/b2c2/flexcop-pci.c @@ -242,19 +242,16 @@ static int flexcop_pci_dma_init(struct flexcop_pci *fc_pci) if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[0],FC_DEFAULT_DMA1_BUFSIZE)) != 0) return ret; - if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) - goto dma1_free; + if ((ret = flexcop_dma_allocate(fc_pci->pdev,&fc_pci->dma[1],FC_DEFAULT_DMA2_BUFSIZE)) != 0) { + flexcop_dma_free(&fc_pci->dma[0]); + return ret; + } flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_MEDIA | FC_SRAM_DEST_NET, FC_SRAM_DEST_TARGET_DMA1); flexcop_sram_set_dest(fc_pci->fc_dev,FC_SRAM_DEST_CAO | FC_SRAM_DEST_CAI, FC_SRAM_DEST_TARGET_DMA2); fc_pci->init_state |= FC_PCI_DMA_INIT; - goto success; -dma1_free: - flexcop_dma_free(&fc_pci->dma[0]); - -success: return ret; } @@ -303,7 +300,7 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci) spin_lock_init(&fc_pci->irq_lock); fc_pci->init_state |= FC_PCI_INIT; - goto success; + return ret; err_pci_iounmap: pci_iounmap(fc_pci->pdev, fc_pci->io_mem); @@ -312,8 +309,6 @@ err_pci_release_regions: pci_release_regions(fc_pci->pdev); err_pci_disable_device: pci_disable_device(fc_pci->pdev); - -success: return ret; } @@ -378,14 +373,14 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e INIT_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work, fc_pci); - goto success; + return ret; + err_fc_exit: flexcop_device_exit(fc); err_pci_exit: flexcop_pci_exit(fc_pci); err_kfree: flexcop_device_kfree(fc); -success: return ret; } diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c index 06ec9fff0ec..515954f96c9 100644 --- a/drivers/media/dvb/b2c2/flexcop-usb.c +++ b/drivers/media/dvb/b2c2/flexcop-usb.c @@ -433,11 +433,10 @@ static int flexcop_usb_transfer_init(struct flexcop_usb *fc_usb) flexcop_wan_set_speed(fc_usb->fc_dev,FC_WAN_SPEED_8MBITS); flexcop_sram_ctrl(fc_usb->fc_dev,1,1,1); - ret = 0; - goto success; + return 0; + urb_error: flexcop_usb_transfer_exit(fc_usb); -success: return ret; } @@ -515,15 +514,14 @@ static int flexcop_usb_probe(struct usb_interface *intf, goto err_fc_exit; info("%s successfully initialized and connected.",DRIVER_NAME); - ret = 0; - goto success; + return 0; + err_fc_exit: flexcop_device_exit(fc); err_usb_exit: flexcop_usb_exit(fc_usb); err_kfree: flexcop_device_kfree(fc); -success: return ret; } diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c index 56ba5247067..29ec4183118 100644 --- a/drivers/media/dvb/b2c2/flexcop.c +++ b/drivers/media/dvb/b2c2/flexcop.c @@ -67,7 +67,7 @@ static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed) static int flexcop_dvb_init(struct flexcop_device *fc) { int ret; - if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner)) < 0) { + if ((ret = dvb_register_adapter(&fc->dvb_adapter,"FlexCop Digital TV device",fc->owner,fc->dev)) < 0) { err("error registering DVB adapter"); return ret; } @@ -116,7 +116,7 @@ static int flexcop_dvb_init(struct flexcop_device *fc) dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx); fc->init_state |= FC_STATE_DVB_INIT; - goto success; + return 0; err_connect_frontend: fc->demux.dmx.remove_frontend(&fc->demux.dmx,&fc->mem_frontend); @@ -129,9 +129,6 @@ err_dmx_dev: err_dmx: dvb_unregister_adapter(&fc->dvb_adapter); return ret; - -success: - return 0; } static void flexcop_dvb_exit(struct flexcop_device *fc) @@ -279,11 +276,10 @@ int flexcop_device_initialize(struct flexcop_device *fc) flexcop_device_name(fc,"initialization of","complete"); - ret = 0; - goto success; + return 0; + error: flexcop_device_exit(fc); -success: return ret; } EXPORT_SYMBOL(flexcop_device_initialize); diff --git a/drivers/media/dvb/bt8xx/bt878.c b/drivers/media/dvb/bt8xx/bt878.c index 5500f8a0ffe..761fa6e7d76 100644 --- a/drivers/media/dvb/bt8xx/bt878.c +++ b/drivers/media/dvb/bt8xx/bt878.c @@ -63,8 +63,6 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging, default is 0 (off)."); int bt878_num; struct bt878 bt878[BT878_MAX]; -EXPORT_SYMBOL(bt878_debug); -EXPORT_SYMBOL(bt878_verbose); EXPORT_SYMBOL(bt878_num); EXPORT_SYMBOL(bt878); @@ -393,7 +391,9 @@ static struct cards card_list[] __devinitdata = { { 0x07711461, BTTV_BOARD_AVDVBT_771, "AVermedia AverTV DVB-T 771" }, { 0xdb1018ac, BTTV_BOARD_DVICO_DVBT_LITE, "DViCO FusionHDTV DVB-T Lite" }, { 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" }, - { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV"}, + { 0x20007063, BTTV_BOARD_PC_HDTV, "pcHDTV HD-2000 TV" }, + { 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini" }, + { 0, -1, NULL } }; @@ -417,6 +417,11 @@ static int __devinit bt878_probe(struct pci_dev *dev, printk(KERN_INFO "bt878: Bt878 AUDIO function found (%d).\n", bt878_num); + if (bt878_num >= BT878_MAX) { + printk(KERN_ERR "bt878: Too many devices inserted\n"); + result = -ENOMEM; + goto fail0; + } if (pci_enable_device(dev)) return -EIO; diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c index 1cfa5e5035d..d687a14ec0a 100644 --- a/drivers/media/dvb/bt8xx/dst.c +++ b/drivers/media/dvb/bt8xx/dst.c @@ -38,6 +38,10 @@ static unsigned int dst_addons; module_param(dst_addons, int, 0644); MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); +static unsigned int dst_algo; +module_param(dst_algo, int, 0644); +MODULE_PARM_DESC(dst_algo, "tuning algo: default is 0=(SW), 1=(HW)"); + #define HAS_LOCK 1 #define ATTEMPT_TUNE 2 #define HAS_POWER 4 @@ -47,20 +51,24 @@ MODULE_PARM_DESC(dst_addons, "CA daughterboard, default is 0 (No addons)"); #define DST_INFO 2 #define DST_DEBUG 3 -#define dprintk(x, y, z, format, arg...) do { \ - if (z) { \ - if ((x > DST_ERROR) && (x > y)) \ - printk(KERN_ERR "%s: " format "\n", __FUNCTION__ , ##arg); \ - else if ((x > DST_NOTICE) && (x > y)) \ - printk(KERN_NOTICE "%s: " format "\n", __FUNCTION__ , ##arg); \ - else if ((x > DST_INFO) && (x > y)) \ - printk(KERN_INFO "%s: " format "\n", __FUNCTION__ , ##arg); \ - else if ((x > DST_DEBUG) && (x > y)) \ - printk(KERN_DEBUG "%s: " format "\n", __FUNCTION__ , ##arg); \ - } else { \ - if (x > y) \ - printk(format, ##arg); \ - } \ +#define dprintk(x, y, z, format, arg...) do { \ + if (z) { \ + if ((x > DST_ERROR) && (x > y)) \ + printk(KERN_ERR "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + else if ((x > DST_NOTICE) && (x > y)) \ + printk(KERN_NOTICE "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + else if ((x > DST_INFO) && (x > y)) \ + printk(KERN_INFO "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + else if ((x > DST_DEBUG) && (x > y)) \ + printk(KERN_DEBUG "dst(%d) %s: " format "\n", \ + state->bt->nr, __func__ , ##arg); \ + } else { \ + if (x > y) \ + printk(format, ##arg); \ + } \ } while(0) @@ -110,7 +118,7 @@ int dst_gpio_inb(struct dst_state *state, u8 *result) *result = 0; if ((err = bt878_device_control(state->bt, DST_IG_READ, &rd_packet)) < 0) { - dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)\n", err); + dprintk(verbose, DST_ERROR, 1, "dst_gpio_inb error (err == %i)", err); return -EREMOTEIO; } *result = (u8) rd_packet.rd.value; @@ -363,6 +371,17 @@ static int dst_set_freq(struct dst_state *state, u32 freq) state->tx_tuna[2] = (freq >> 16) & 0xff; state->tx_tuna[3] = (freq >> 8) & 0xff; state->tx_tuna[4] = (u8) freq; + } else if (state->dst_type == DST_TYPE_IS_ATSC) { + freq = freq / 1000; + if (freq < 51000 || freq > 858000) + return -EINVAL; + state->tx_tuna[2] = (freq >> 16) & 0xff; + state->tx_tuna[3] = (freq >> 8) & 0xff; + state->tx_tuna[4] = (u8) freq; + state->tx_tuna[5] = 0x00; /* ATSC */ + state->tx_tuna[6] = 0x00; + if (state->dst_hw_cap & DST_TYPE_HAS_ANALOG) + state->tx_tuna[7] = 0x00; /* Digital */ } else return -EINVAL; @@ -447,29 +466,41 @@ static int dst_set_symbolrate(struct dst_state *state, u32 srate) } dprintk(verbose, DST_INFO, 1, "set symrate %u", srate); srate /= 1000; - if (state->type_flags & DST_TYPE_HAS_SYMDIV) { - sval = srate; - sval <<= 20; - do_div(sval, 88000); - symcalc = (u32) sval; - dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); - state->tx_tuna[5] = (u8) (symcalc >> 12); - state->tx_tuna[6] = (u8) (symcalc >> 4); - state->tx_tuna[7] = (u8) (symcalc << 4); - } else { - state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; - state->tx_tuna[6] = (u8) (srate >> 8); - state->tx_tuna[7] = (u8) srate; - } - state->tx_tuna[8] &= ~0x20; - if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { - if (srate > 8000) - state->tx_tuna[8] |= 0x20; + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_SYMDIV) { + sval = srate; + sval <<= 20; + do_div(sval, 88000); + symcalc = (u32) sval; + dprintk(verbose, DST_INFO, 1, "set symcalc %u", symcalc); + state->tx_tuna[5] = (u8) (symcalc >> 12); + state->tx_tuna[6] = (u8) (symcalc >> 4); + state->tx_tuna[7] = (u8) (symcalc << 4); + } else { + state->tx_tuna[5] = (u8) (srate >> 16) & 0x7f; + state->tx_tuna[6] = (u8) (srate >> 8); + state->tx_tuna[7] = (u8) srate; + } + state->tx_tuna[8] &= ~0x20; + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) { + if (srate > 8000) + state->tx_tuna[8] |= 0x20; + } + } else if (state->dst_type == DST_TYPE_IS_CABLE) { + dprintk(verbose, DST_DEBUG, 1, "%s", state->fw_name); + if (!strncmp(state->fw_name, "DCTNEW", 6)) { + state->tx_tuna[5] = (u8) (srate >> 8); + state->tx_tuna[6] = (u8) srate; + state->tx_tuna[7] = 0x00; + } else if (!strncmp(state->fw_name, "DCT-CI", 6)) { + state->tx_tuna[5] = 0x00; + state->tx_tuna[6] = (u8) (srate >> 8); + state->tx_tuna[7] = (u8) srate; + } } return 0; } - static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulation) { if (state->dst_type != DST_TYPE_IS_CABLE) @@ -490,7 +521,10 @@ static int dst_set_modulation(struct dst_state *state, fe_modulation_t modulatio state->tx_tuna[8] = 0x80; break; case QAM_256: - state->tx_tuna[8] = 0x00; + if (!strncmp(state->fw_name, "DCTNEW", 6)) + state->tx_tuna[8] = 0xff; + else if (!strncmp(state->fw_name, "DCT-CI", 6)) + state->tx_tuna[8] = 0x00; break; case QPSK: case QAM_AUTO: @@ -523,13 +557,19 @@ u8 dst_check_sum(u8 *buf, u32 len) } EXPORT_SYMBOL(dst_check_sum); -static void dst_type_flags_print(u32 type_flags) +static void dst_type_flags_print(struct dst_state *state) { + u32 type_flags = state->type_flags; + dprintk(verbose, DST_ERROR, 0, "DST type flags :"); - if (type_flags & DST_TYPE_HAS_NEWTUNE) - dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_NEWTUNE); + if (type_flags & DST_TYPE_HAS_TS188) + dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner", DST_TYPE_HAS_TS188); + if (type_flags & DST_TYPE_HAS_NEWTUNE_2) + dprintk(verbose, DST_ERROR, 0, " 0x%x newtuner 2", DST_TYPE_HAS_NEWTUNE_2); if (type_flags & DST_TYPE_HAS_TS204) dprintk(verbose, DST_ERROR, 0, " 0x%x ts204", DST_TYPE_HAS_TS204); + if (type_flags & DST_TYPE_HAS_VLF) + dprintk(verbose, DST_ERROR, 0, " 0x%x VLF", DST_TYPE_HAS_VLF); if (type_flags & DST_TYPE_HAS_SYMDIV) dprintk(verbose, DST_ERROR, 0, " 0x%x symdiv", DST_TYPE_HAS_SYMDIV); if (type_flags & DST_TYPE_HAS_FW_1) @@ -542,7 +582,7 @@ static void dst_type_flags_print(u32 type_flags) } -static int dst_type_print(u8 type) +static int dst_type_print(struct dst_state *state, u8 type) { char *otype; switch (type) { @@ -558,6 +598,10 @@ static int dst_type_print(u8 type) otype = "cable"; break; + case DST_TYPE_IS_ATSC: + otype = "atsc"; + break; + default: dprintk(verbose, DST_INFO, 1, "invalid dst type %d", type); return -EINVAL; @@ -567,6 +611,127 @@ static int dst_type_print(u8 type) return 0; } +struct tuner_types tuner_list[] = { + { + .tuner_type = TUNER_TYPE_L64724, + .tuner_name = "L 64724", + .board_name = "UNKNOWN", + .fw_name = "UNKNOWN" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1020", + .fw_name = "DST-MOT" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1020", + .fw_name = "DST-03T" + }, + + { + .tuner_type = TUNER_TYPE_MB86A15, + .tuner_name = "MB 86A15", + .board_name = "VP1022", + .fw_name = "DST-03T" + }, + + { + .tuner_type = TUNER_TYPE_MB86A15, + .tuner_name = "MB 86A15", + .board_name = "VP1025", + .fw_name = "DST-03T" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1030", + .fw_name = "DST-CI" + }, + + { + .tuner_type = TUNER_TYPE_STV0299, + .tuner_name = "STV 0299", + .board_name = "VP1030", + .fw_name = "DSTMCI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2021", + .fw_name = "DCTNEW" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2030", + .fw_name = "DCT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2031", + .fw_name = "DCT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP2040", + .fw_name = "DCT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP3020", + .fw_name = "DTTFTA" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP3021", + .fw_name = "DTTFTA" + }, + + { + .tuner_type = TUNER_TYPE_TDA10046, + .tuner_name = "TDA10046", + .board_name = "VP3040", + .fw_name = "DTT-CI" + }, + + { + .tuner_type = TUNER_TYPE_UNKNOWN, + .tuner_name = "UNKNOWN", + .board_name = "VP3051", + .fw_name = "DTTNXT" + }, + + { + .tuner_type = TUNER_TYPE_NXT200x, + .tuner_name = "NXT200x", + .board_name = "VP3220", + .fw_name = "ATSCDI" + }, + + { + .tuner_type = TUNER_TYPE_NXT200x, + .tuner_name = "NXT200x", + .board_name = "VP3250", + .fw_name = "ATSCAD" + }, +}; + /* Known cards list Satellite @@ -608,7 +773,8 @@ static struct dst_types dst_tlist[] = { .offset = 0, .dst_type = DST_TYPE_IS_SAT, .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_OBS_REGS, - .dst_feature = 0 + .dst_feature = 0, + .tuner_type = 0 }, /* obsolete */ { @@ -616,15 +782,17 @@ static struct dst_types dst_tlist[] = { .offset = 0, .dst_type = DST_TYPE_IS_SAT, .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, - .dst_feature = 0 + .dst_feature = 0, + .tuner_type = 0 }, /* obsolete */ { .device_id = "DST-030", .offset = 0, .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, - .dst_feature = 0 + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, + .dst_feature = 0, + .tuner_type = 0 }, /* obsolete */ { @@ -633,7 +801,8 @@ static struct dst_types dst_tlist[] = { .dst_type = DST_TYPE_IS_SAT, .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_2, .dst_feature = DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 | DST_TYPE_HAS_DISEQC5 - | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO + | DST_TYPE_HAS_MAC | DST_TYPE_HAS_MOTO, + .tuner_type = TUNER_TYPE_MULTI }, { @@ -641,57 +810,63 @@ static struct dst_types dst_tlist[] = { .offset = 0, .dst_type = DST_TYPE_IS_SAT, .type_flags = DST_TYPE_HAS_SYMDIV | DST_TYPE_HAS_FW_1, - .dst_feature = 0 + .dst_feature = 0, + .tuner_type = 0 }, /* obsolete */ { .device_id = "DST-CI", .offset = 1, .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, - .dst_feature = DST_TYPE_HAS_CA + .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_FW_1, + .dst_feature = DST_TYPE_HAS_CA, + .tuner_type = 0 }, /* An OEM board */ { .device_id = "DSTMCI", .offset = 1, .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT, + .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_INC_COUNT | DST_TYPE_HAS_VLF, .dst_feature = DST_TYPE_HAS_CA | DST_TYPE_HAS_DISEQC3 | DST_TYPE_HAS_DISEQC4 - | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC + | DST_TYPE_HAS_MOTO | DST_TYPE_HAS_MAC, + .tuner_type = TUNER_TYPE_MULTI }, { .device_id = "DSTFCI", .offset = 1, .dst_type = DST_TYPE_IS_SAT, - .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1, - .dst_feature = 0 + .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_1, + .dst_feature = 0, + .tuner_type = 0 }, /* unknown to vendor */ { .device_id = "DCT-CI", .offset = 1, .dst_type = DST_TYPE_IS_CABLE, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_1 - | DST_TYPE_HAS_FW_2, - .dst_feature = DST_TYPE_HAS_CA + .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_1 | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_VLF, + .dst_feature = DST_TYPE_HAS_CA, + .tuner_type = 0 }, { .device_id = "DCTNEW", .offset = 1, .dst_type = DST_TYPE_IS_CABLE, - .type_flags = DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD, - .dst_feature = 0 + .type_flags = DST_TYPE_HAS_TS188 | DST_TYPE_HAS_FW_3 | DST_TYPE_HAS_FW_BUILD | DST_TYPE_HAS_MULTI_FE, + .dst_feature = 0, + .tuner_type = 0 }, { .device_id = "DTT-CI", .offset = 1, .dst_type = DST_TYPE_IS_TERR, - .type_flags = DST_TYPE_HAS_TS204 | DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE, - .dst_feature = DST_TYPE_HAS_CA + .type_flags = DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_VLF, + .dst_feature = DST_TYPE_HAS_CA, + .tuner_type = 0 }, { @@ -699,7 +874,8 @@ static struct dst_types dst_tlist[] = { .offset = 1, .dst_type = DST_TYPE_IS_TERR, .type_flags = DST_TYPE_HAS_FW_2, - .dst_feature = 0 + .dst_feature = 0, + .tuner_type = 0 }, { @@ -707,7 +883,8 @@ static struct dst_types dst_tlist[] = { .offset = 1, .dst_type = DST_TYPE_IS_TERR, .type_flags = DST_TYPE_HAS_FW_2, - .dst_feature = DST_TYPE_HAS_ANALOG + .dst_feature = DST_TYPE_HAS_ANALOG, + .tuner_type = 0 }, { @@ -715,15 +892,17 @@ static struct dst_types dst_tlist[] = { .offset = 1, .dst_type = DST_TYPE_IS_ATSC, .type_flags = DST_TYPE_HAS_FW_2, - .dst_feature = 0 + .dst_feature = 0, + .tuner_type = 0 }, { .device_id = "ATSCAD", .offset = 1, .dst_type = DST_TYPE_IS_ATSC, - .type_flags = DST_TYPE_HAS_FW_2, - .dst_feature = 0 + .type_flags = DST_TYPE_HAS_MULTI_FE | DST_TYPE_HAS_FW_2 | DST_TYPE_HAS_FW_BUILD, + .dst_feature = DST_TYPE_HAS_MAC | DST_TYPE_HAS_ANALOG, + .tuner_type = 0 }, { } @@ -768,6 +947,9 @@ static int dst_fw_ver(struct dst_state *state) static int dst_card_type(struct dst_state *state) { + int j; + struct tuner_types *p_tuner_list = NULL; + u8 get_type[] = { 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; get_type[7] = dst_check_sum(get_type, 7); if (dst_command(state, get_type, 8) < 0) { @@ -775,9 +957,17 @@ static int dst_card_type(struct dst_state *state) return -1; } memset(&state->card_info, '\0', 8); - memcpy(&state->card_info, &state->rxbuffer, 8); + memcpy(&state->card_info, &state->rxbuffer, 7); dprintk(verbose, DST_ERROR, 1, "Device Model=[%s]", &state->card_info[0]); + for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { + if (!strcmp(&state->card_info[0], p_tuner_list->board_name)) { + state->tuner_type = p_tuner_list->tuner_type; + dprintk(verbose, DST_ERROR, 1, "DST has [%s] tuner, tuner type=[%d]", + p_tuner_list->tuner_name, p_tuner_list->tuner_type); + } + } + return 0; } @@ -790,12 +980,64 @@ static int dst_get_vendor(struct dst_state *state) return -1; } memset(&state->vendor, '\0', 8); - memcpy(&state->vendor, &state->rxbuffer, 8); + memcpy(&state->vendor, &state->rxbuffer, 7); dprintk(verbose, DST_ERROR, 1, "Vendor=[%s]", &state->vendor[0]); return 0; } +static void debug_dst_buffer(struct dst_state *state) +{ + int i; + + if (verbose > 2) { + printk("%s: [", __func__); + for (i = 0; i < 8; i++) + printk(" %02x", state->rxbuffer[i]); + printk("]\n"); + } +} + +static int dst_check_stv0299(struct dst_state *state) +{ + u8 check_stv0299[] = { 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + check_stv0299[7] = dst_check_sum(check_stv0299, 7); + if (dst_command(state, check_stv0299, 8) < 0) { + dprintk(verbose, DST_ERROR, 1, "Cmd=[0x04] failed"); + return -1; + } + debug_dst_buffer(state); + + if (memcmp(&check_stv0299, &state->rxbuffer, 8)) { + dprintk(verbose, DST_ERROR, 1, "Found a STV0299 NIM"); + state->tuner_type = TUNER_TYPE_STV0299; + return 0; + } + + return -1; +} + +static int dst_check_mb86a15(struct dst_state *state) +{ + u8 check_mb86a15[] = { 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + + check_mb86a15[7] = dst_check_sum(check_mb86a15, 7); + if (dst_command(state, check_mb86a15, 8) < 0) { + dprintk(verbose, DST_ERROR, 1, "Cmd=[0x10], failed"); + return -1; + } + debug_dst_buffer(state); + + if (memcmp(&check_mb86a15, &state->rxbuffer, 8) < 0) { + dprintk(verbose, DST_ERROR, 1, "Found a MB86A15 NIM"); + state->tuner_type = TUNER_TYPE_MB86A15; + return 0; + } + + return -1; +} + static int dst_get_tuner_info(struct dst_state *state) { u8 get_tuner_1[] = { 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; @@ -803,60 +1045,59 @@ static int dst_get_tuner_info(struct dst_state *state) get_tuner_1[7] = dst_check_sum(get_tuner_1, 7); get_tuner_2[7] = dst_check_sum(get_tuner_2, 7); + dprintk(verbose, DST_ERROR, 1, "DST TYpe = MULTI FE"); if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { - if (dst_command(state, get_tuner_2, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); - return -1; + if (dst_command(state, get_tuner_1, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Cmd=[0x13], Unsupported"); + goto force; } } else { - if (dst_command(state, get_tuner_1, 8) < 0) { - dprintk(verbose, DST_INFO, 1, "Unsupported Command"); - return -1; + if (dst_command(state, get_tuner_2, 8) < 0) { + dprintk(verbose, DST_INFO, 1, "Cmd=[0xb], Unsupported"); + goto force; } } memset(&state->board_info, '\0', 8); memcpy(&state->board_info, &state->rxbuffer, 8); if (state->type_flags & DST_TYPE_HAS_MULTI_FE) { - if (state->board_info[1] == 0x0b) { - if (state->type_flags & DST_TYPE_HAS_TS204) - state->type_flags &= ~DST_TYPE_HAS_TS204; - state->type_flags |= DST_TYPE_HAS_NEWTUNE; - dprintk(verbose, DST_INFO, 1, "DST type has TS=188"); - } else { - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) - state->type_flags &= ~DST_TYPE_HAS_NEWTUNE; - state->type_flags |= DST_TYPE_HAS_TS204; - dprintk(verbose, DST_INFO, 1, "DST type has TS=204"); - } - } else { - if (state->board_info[0] == 0xbc) { - if (state->type_flags & DST_TYPE_HAS_TS204) - state->type_flags &= ~DST_TYPE_HAS_TS204; - state->type_flags |= DST_TYPE_HAS_NEWTUNE; - dprintk(verbose, DST_INFO, 1, "DST type has TS=188, Daughterboard=[%d]", state->board_info[1]); - - } else if (state->board_info[0] == 0xcc) { - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) - state->type_flags &= ~DST_TYPE_HAS_NEWTUNE; - state->type_flags |= DST_TYPE_HAS_TS204; - dprintk(verbose, DST_INFO, 1, "DST type has TS=204 Daughterboard=[%d]", state->board_info[1]); + dprintk(verbose, DST_ERROR, 1, "DST type has TS=188"); + } + if (state->board_info[0] == 0xbc) { + if (state->type_flags != DST_TYPE_IS_ATSC) + state->type_flags |= DST_TYPE_HAS_TS188; + else + state->type_flags |= DST_TYPE_HAS_NEWTUNE_2; + + if (state->board_info[1] == 0x01) { + state->dst_hw_cap |= DST_TYPE_HAS_DBOARD; + dprintk(verbose, DST_ERROR, 1, "DST has Daughterboard"); } } return 0; +force: + if (!strncmp(state->fw_name, "DCT-CI", 6)) { + state->type_flags |= DST_TYPE_HAS_TS204; + dprintk(verbose, DST_ERROR, 1, "Forcing [%s] to TS188", state->fw_name); + } + + return -1; } static int dst_get_device_id(struct dst_state *state) { u8 reply; - int i; - struct dst_types *p_dst_type; + int i, j; + struct dst_types *p_dst_type = NULL; + struct tuner_types *p_tuner_list = NULL; + u8 use_dst_type = 0; u32 use_type_flags = 0; static u8 device_type[8] = {0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff}; + state->tuner_type = 0; device_type[7] = dst_check_sum(device_type, 7); if (write_dst(state, device_type, FIXED_COMM)) @@ -888,8 +1129,34 @@ static int dst_get_device_id(struct dst_state *state) /* Card capabilities */ state->dst_hw_cap = p_dst_type->dst_feature; - dprintk(verbose, DST_ERROR, 1, "Recognise [%s]\n", p_dst_type->device_id); - + dprintk(verbose, DST_ERROR, 1, "Recognise [%s]", p_dst_type->device_id); + strncpy(&state->fw_name[0], p_dst_type->device_id, 6); + /* Multiple tuners */ + if (p_dst_type->tuner_type & TUNER_TYPE_MULTI) { + switch (use_dst_type) { + case DST_TYPE_IS_SAT: + /* STV0299 check */ + if (dst_check_stv0299(state) < 0) { + dprintk(verbose, DST_ERROR, 1, "Unsupported"); + state->tuner_type = TUNER_TYPE_MB86A15; + } + break; + default: + break; + } + if (dst_check_mb86a15(state) < 0) + dprintk(verbose, DST_ERROR, 1, "Unsupported"); + /* Single tuner */ + } else { + state->tuner_type = p_dst_type->tuner_type; + } + for (j = 0, p_tuner_list = tuner_list; j < ARRAY_SIZE(tuner_list); j++, p_tuner_list++) { + if (!(strncmp(p_dst_type->device_id, p_tuner_list->fw_name, 7)) && + p_tuner_list->tuner_type == state->tuner_type) { + dprintk(verbose, DST_ERROR, 1, "[%s] has a [%s]", + p_dst_type->device_id, p_tuner_list->tuner_name); + } + } break; } } @@ -900,10 +1167,10 @@ static int dst_get_device_id(struct dst_state *state) use_dst_type = DST_TYPE_IS_SAT; use_type_flags = DST_TYPE_HAS_SYMDIV; } - dst_type_print(use_dst_type); + dst_type_print(state, use_dst_type); state->type_flags = use_type_flags; state->dst_type = use_dst_type; - dst_type_flags_print(state->type_flags); + dst_type_flags_print(state); return 0; } @@ -911,15 +1178,15 @@ static int dst_get_device_id(struct dst_state *state) static int dst_probe(struct dst_state *state) { mutex_init(&state->dst_mutex); - if ((rdc_8820_reset(state)) < 0) { - dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); - return -1; - } - if (dst_addons & DST_TYPE_HAS_CA) + if (dst_addons & DST_TYPE_HAS_CA) { + if ((rdc_8820_reset(state)) < 0) { + dprintk(verbose, DST_ERROR, 1, "RDC 8820 RESET Failed."); + return -1; + } msleep(4000); - else + } else { msleep(100); - + } if ((dst_comm_init(state)) < 0) { dprintk(verbose, DST_ERROR, 1, "DST Initialization Failed."); return -1; @@ -931,7 +1198,6 @@ static int dst_probe(struct dst_state *state) } if (dst_get_mac(state) < 0) { dprintk(verbose, DST_INFO, 1, "MAC: Unsupported command"); - return 0; } if ((state->type_flags & DST_TYPE_HAS_MULTI_FE) || (state->type_flags & DST_TYPE_HAS_FW_BUILD)) { if (dst_get_tuner_info(state) < 0) @@ -1048,6 +1314,10 @@ static int dst_get_signal(struct dst_state *state) state->decode_lock = (state->rxbuffer[1]) ? 1 : 0; state->decode_strength = state->rxbuffer[4] << 8; state->decode_snr = state->rxbuffer[3] << 8; + } else if (state->dst_type == DST_TYPE_IS_ATSC) { + state->decode_lock = (state->rxbuffer[6] == 0x00) ? 1 : 0; + state->decode_strength = state->rxbuffer[4] << 8; + state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3]; } state->cur_jiff = jiffies; } @@ -1078,8 +1348,9 @@ static int dst_get_tuna(struct dst_state *state) state->diseq_flags &= ~(HAS_LOCK); if (!dst_wait_dst_ready(state, NO_DELAY)) return -EIO; - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) - /* how to get variable length reply ???? */ + if ((state->type_flags & DST_TYPE_HAS_VLF) && + !(state->dst_type == DST_TYPE_IS_ATSC)) + retval = read_dst(state, state->rx_tuna, 10); else retval = read_dst(state, &state->rx_tuna[2], FIXED_COMM); @@ -1087,7 +1358,10 @@ static int dst_get_tuna(struct dst_state *state) dprintk(verbose, DST_DEBUG, 1, "read not successful"); return retval; } - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + if ((state->type_flags & DST_TYPE_HAS_VLF) && + !(state->dst_type == DST_TYPE_IS_CABLE) && + !(state->dst_type == DST_TYPE_IS_ATSC)) { + if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) { dprintk(verbose, DST_INFO, 1, "checksum failure ? "); return -EIO; @@ -1133,7 +1407,10 @@ static int dst_write_tuna(struct dvb_frontend *fe) dprintk(verbose, DST_DEBUG, 1, "DST Communication initialization failed."); goto error; } - if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { +// if (state->type_flags & DST_TYPE_HAS_NEWTUNE) { + if ((state->type_flags & DST_TYPE_HAS_VLF) && + (!(state->dst_type == DST_TYPE_IS_ATSC))) { + state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9); retval = write_dst(state, &state->tx_tuna[0], 10); } else { @@ -1189,9 +1466,12 @@ static int dst_set_diseqc(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd if (state->dst_type != DST_TYPE_IS_SAT) return 0; - if (cmd->msg_len == 0 || cmd->msg_len > 4) + if (cmd->msg_len > 0 && cmd->msg_len < 5) + memcpy(&paket[3], cmd->msg, cmd->msg_len); + else if (cmd->msg_len == 5 && state->dst_hw_cap & DST_TYPE_HAS_DISEQC5) + memcpy(&paket[2], cmd->msg, cmd->msg_len); + else 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; @@ -1287,8 +1567,9 @@ static int dst_init(struct dvb_frontend *fe) static u8 sat_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x55, 0xbd, 0x50, 0x00, 0x00 }; static u8 ter_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; static u8 ter_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; - static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; static u8 cab_tuna_188[] = { 0x09, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 cab_tuna_204[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; + static u8 atsc_tuner[] = { 0x00, 0x00, 0x03, 0xb6, 0x01, 0x07, 0x00, 0x00, 0x00, 0x00 }; state->inversion = INVERSION_OFF; state->voltage = SEC_VOLTAGE_13; @@ -1298,11 +1579,13 @@ static int dst_init(struct dvb_frontend *fe) state->bandwidth = BANDWIDTH_7_MHZ; state->cur_jiff = jiffies; if (state->dst_type == DST_TYPE_IS_SAT) - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? sat_tuna_188 : sat_tuna_204), sizeof (sat_tuna_204)); else if (state->dst_type == DST_TYPE_IS_TERR) - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? ter_tuna_188 : ter_tuna_204), sizeof (ter_tuna_204)); else if (state->dst_type == DST_TYPE_IS_CABLE) - memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_NEWTUNE) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); + memcpy(state->tx_tuna, ((state->type_flags & DST_TYPE_HAS_VLF) ? cab_tuna_188 : cab_tuna_204), sizeof (cab_tuna_204)); + else if (state->dst_type == DST_TYPE_IS_ATSC) + memcpy(state->tx_tuna, atsc_tuner, sizeof (atsc_tuner)); return 0; } @@ -1341,7 +1624,36 @@ static int dst_read_snr(struct dvb_frontend *fe, u16 *snr) return 0; } -static int dst_set_frontend(struct dvb_frontend* fe, +static int dst_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) +{ + struct dst_state *state = fe->demodulator_priv; + + if (p != NULL) { + dst_set_freq(state, p->frequency); + dprintk(verbose, DST_DEBUG, 1, "Set Frequency=[%d]", p->frequency); + + if (state->dst_type == DST_TYPE_IS_SAT) { + if (state->type_flags & DST_TYPE_HAS_OBS_REGS) + dst_set_inversion(state, p->inversion); + dst_set_fec(state, p->u.qpsk.fec_inner); + dst_set_symbolrate(state, p->u.qpsk.symbol_rate); + dst_set_polarization(state); + dprintk(verbose, DST_DEBUG, 1, "Set Symbolrate=[%d]", 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_set_modulation(state, p->u.qam.modulation); + } + dst_write_tuna(fe); + } + + return 0; +} + +static int dst_tune_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* p, unsigned int mode_flags, int *delay, @@ -1378,6 +1690,11 @@ static int dst_set_frontend(struct dvb_frontend* fe, return 0; } +static int dst_get_tuning_algo(struct dvb_frontend *fe) +{ + return dst_algo; +} + static int dst_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_parameters *p) { struct dst_state *state = fe->demodulator_priv; @@ -1408,6 +1725,7 @@ static void dst_release(struct dvb_frontend *fe) static struct dvb_frontend_ops dst_dvbt_ops; static struct dvb_frontend_ops dst_dvbs_ops; static struct dvb_frontend_ops dst_dvbc_ops; +static struct dvb_frontend_ops dst_atsc_ops; struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_adapter) { @@ -1417,24 +1735,25 @@ struct dst_state *dst_attach(struct dst_state *state, struct dvb_adapter *dvb_ad return NULL; } /* determine settings based on type */ + /* create dvb_frontend */ switch (state->dst_type) { case DST_TYPE_IS_TERR: - memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.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)); + memcpy(&state->frontend.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)); + memcpy(&state->frontend.ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops)); + break; + case DST_TYPE_IS_ATSC: + memcpy(&state->frontend.ops, &dst_atsc_ops, sizeof(struct dvb_frontend_ops)); break; default: dprintk(verbose, DST_ERROR, 1, "unknown DST type. please report to the LinuxTV.org DVB mailinglist."); kfree(state); return NULL; } - - /* create dvb_frontend */ - state->frontend.ops = &state->ops; state->frontend.demodulator_priv = state; return state; /* Manu (DST is a card not a frontend) */ @@ -1455,8 +1774,10 @@ static struct dvb_frontend_ops dst_dvbt_ops = { .release = dst_release, .init = dst_init, - .tune = dst_set_frontend, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, .read_snr = dst_read_snr, @@ -1479,8 +1800,10 @@ static struct dvb_frontend_ops dst_dvbs_ops = { .release = dst_release, .init = dst_init, - .tune = dst_set_frontend, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, .read_status = dst_read_status, .read_signal_strength = dst_read_signal_strength, .read_snr = dst_read_snr, @@ -1506,13 +1829,38 @@ static struct dvb_frontend_ops dst_dvbc_ops = { .release = dst_release, .init = dst_init, - .tune = dst_set_frontend, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, + .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, + .read_status = dst_read_status, + .read_signal_strength = dst_read_signal_strength, + .read_snr = dst_read_snr, +}; + +static struct dvb_frontend_ops dst_atsc_ops = { + .info = { + .name = "DST ATSC", + .type = FE_ATSC, + .frequency_stepsize = 62500, + .frequency_min = 510000000, + .frequency_max = 858000000, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB + }, + + .release = dst_release, + .init = dst_init, + .tune = dst_tune_frontend, + .set_frontend = dst_set_frontend, .get_frontend = dst_get_frontend, + .get_frontend_algo = dst_get_tuning_algo, .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_DESCRIPTION("DST DVB-S/T/C/ATSC Combo Frontend driver"); MODULE_AUTHOR("Jamie Honan, Manu Abraham"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c index f6b49a801eb..fa923b9b346 100644 --- a/drivers/media/dvb/bt8xx/dst_ca.c +++ b/drivers/media/dvb/bt8xx/dst_ca.c @@ -68,6 +68,13 @@ static int ca_set_pid(void) return -EOPNOTSUPP; } +static void put_command_and_length(u8 *data, int command, int length) +{ + data[0] = (command >> 16) & 0xff; + data[1] = (command >> 8) & 0xff; + data[2] = command & 0xff; + data[3] = length; +} static void put_checksum(u8 *check_string, int length) { @@ -124,15 +131,18 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, u8 dst_ca_comm_err = 0; while (dst_ca_comm_err < RETRIES) { - dst_comm_init(state); dprintk(verbose, DST_CA_NOTICE, 1, " Put Command"); if (dst_ci_command(state, data, ca_string, len, read)) { // If error dst_error_recovery(state); dst_ca_comm_err++; // work required here. + } else { + break; } - break; } + if(dst_ca_comm_err == RETRIES) + return -1; + return 0; } @@ -140,6 +150,7 @@ static int dst_put_ci(struct dst_state *state, u8 *data, int len, u8 *ca_string, static int ca_get_app_info(struct dst_state *state) { + int length, str_length; static u8 command[8] = {0x07, 0x40, 0x01, 0x00, 0x01, 0x00, 0x00, 0xff}; put_checksum(&command[0], command[0]); @@ -154,6 +165,68 @@ static int ca_get_app_info(struct dst_state *state) (state->messages[10] << 8) | state->messages[11], __FUNCTION__, (char *)(&state->messages[12])); dprintk(verbose, DST_CA_INFO, 1, " =================================================================================================="); + // Transform dst message to correct application_info message + length = state->messages[5]; + str_length = length - 6; + if (str_length < 0) { + str_length = 0; + dprintk(verbose, DST_CA_ERROR, 1, "Invalid string length returned in ca_get_app_info(). Recovering."); + } + + // First, the command and length fields + put_command_and_length(&state->messages[0], CA_APP_INFO, length); + + // Copy application_type, application_manufacturer and manufacturer_code + memcpy(&state->messages[4], &state->messages[7], 5); + + // Set string length and copy string + state->messages[9] = str_length; + memcpy(&state->messages[10], &state->messages[12], str_length); + + return 0; +} + +static int ca_get_ca_info(struct dst_state *state) +{ + int srcPtr, dstPtr, i, num_ids; + static u8 slot_command[8] = {0x07, 0x40, 0x00, 0x00, 0x02, 0x00, 0x00, 0xff}; + const int in_system_id_pos = 8, out_system_id_pos = 4, in_num_ids_pos = 7; + + put_checksum(&slot_command[0], slot_command[0]); + if ((dst_put_ci(state, slot_command, sizeof (slot_command), state->messages, GET_REPLY)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->dst_put_ci FAILED !"); + return -1; + } + dprintk(verbose, DST_CA_INFO, 1, " -->dst_put_ci SUCCESS !"); + + // Print raw data + dprintk(verbose, DST_CA_INFO, 0, " DST data = ["); + for (i = 0; i < state->messages[0] + 1; i++) { + dprintk(verbose, DST_CA_INFO, 0, " 0x%02x", state->messages[i]); + } + dprintk(verbose, DST_CA_INFO, 0, "]\n"); + + // Set the command and length of the output + num_ids = state->messages[in_num_ids_pos]; + if (num_ids >= 100) { + num_ids = 100; + dprintk(verbose, DST_CA_ERROR, 1, "Invalid number of ids (>100). Recovering."); + } + put_command_and_length(&state->messages[0], CA_INFO, num_ids * 2); + + dprintk(verbose, DST_CA_INFO, 0, " CA_INFO = ["); + srcPtr = in_system_id_pos; + dstPtr = out_system_id_pos; + for(i = 0; i < num_ids; i++) { + dprintk(verbose, DST_CA_INFO, 0, " 0x%02x%02x", state->messages[srcPtr + 0], state->messages[srcPtr + 1]); + // Append to output + state->messages[dstPtr + 0] = state->messages[srcPtr + 0]; + state->messages[dstPtr + 1] = state->messages[srcPtr + 1]; + srcPtr += 2; + dstPtr += 2; + } + dprintk(verbose, DST_CA_INFO, 0, "]\n"); + return 0; } @@ -174,7 +247,7 @@ static int ca_get_slot_caps(struct dst_state *state, struct ca_caps *p_ca_caps, dprintk(verbose, DST_CA_INFO, 1, " Slot cap = [%d]", slot_cap[7]); dprintk(verbose, DST_CA_INFO, 0, "===================================\n"); - for (i = 0; i < 8; i++) + for (i = 0; i < slot_cap[0] + 1; i++) dprintk(verbose, DST_CA_INFO, 0, " %d", slot_cap[i]); dprintk(verbose, DST_CA_INFO, 0, "\n"); @@ -260,6 +333,11 @@ static int ca_get_message(struct dst_state *state, struct ca_msg *p_ca_message, if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) return -EFAULT; break; + case CA_INFO: + memcpy(p_ca_message->msg, state->messages, 128); + if (copy_to_user(arg, p_ca_message, sizeof (struct ca_msg)) ) + return -EFAULT; + break; } } @@ -302,7 +380,7 @@ static int write_to_8820(struct dst_state *state, struct ca_msg *hw_buffer, u8 l rdc_reset_state(state); return -1; } - dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command succes."); + dprintk(verbose, DST_CA_NOTICE, 1, " DST-CI Command success."); return 0; } @@ -340,6 +418,7 @@ static int debug_string(u8 *msg, u32 length, u32 offset) return 0; } + static int ca_set_pmt(struct dst_state *state, struct ca_msg *p_ca_message, struct ca_msg *hw_buffer, u8 reply, u8 query) { u32 length = 0; @@ -455,6 +534,16 @@ static int ca_send_message(struct dst_state *state, struct ca_msg *p_ca_message, } dprintk(verbose, DST_CA_INFO, 1, " -->CA_APP_INFO_ENQUIRY Success !"); break; + case CA_INFO_ENQUIRY: + dprintk(verbose, DST_CA_INFO, 1, " Getting CA Information"); + + if ((ca_get_ca_info(state)) < 0) { + dprintk(verbose, DST_CA_ERROR, 1, " -->CA_INFO_ENQUIRY Failed !"); + result = -1; + goto free_mem_and_exit; + } + dprintk(verbose, DST_CA_INFO, 1, " -->CA_INFO_ENQUIRY Success !"); + break; } } free_mem_and_exit: @@ -473,18 +562,15 @@ static int dst_ca_ioctl(struct inode *inode, struct file *file, unsigned int cmd void __user *arg = (void __user *)ioctl_arg; int result = 0; - if ((p_ca_message = (struct ca_msg *) kmalloc(sizeof (struct ca_msg), GFP_KERNEL)) == NULL) { - dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); - return -ENOMEM; - } - if ((p_ca_slot_info = (struct ca_slot_info *) kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL)) == NULL) { + p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL); + p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL); + p_ca_caps = kmalloc(sizeof (struct ca_caps), GFP_KERNEL); + if (!p_ca_message || !p_ca_slot_info || !p_ca_caps) { dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); - return -ENOMEM; - } - if ((p_ca_caps = (struct ca_caps *) kmalloc(sizeof (struct ca_caps), GFP_KERNEL)) == NULL) { - dprintk(verbose, DST_CA_ERROR, 1, " Memory allocation failure"); - return -ENOMEM; + result = -ENOMEM; + goto free_mem_and_exit; } + /* We have now only the standard ioctl's, the driver is upposed to handle internals. */ switch (cmd) { case CA_SEND_MSG: @@ -582,7 +668,7 @@ static int dst_ca_release(struct inode *inode, struct file *file) static ssize_t dst_ca_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) { - int bytes_read = 0; + ssize_t bytes_read = 0; dprintk(verbose, DST_CA_DEBUG, 1, " Device read."); diff --git a/drivers/media/dvb/bt8xx/dst_common.h b/drivers/media/dvb/bt8xx/dst_common.h index 51d4e043716..0677b047b3a 100644 --- a/drivers/media/dvb/bt8xx/dst_common.h +++ b/drivers/media/dvb/bt8xx/dst_common.h @@ -42,7 +42,7 @@ #define DST_TYPE_IS_CABLE 2 #define DST_TYPE_IS_ATSC 3 -#define DST_TYPE_HAS_NEWTUNE 1 +#define DST_TYPE_HAS_TS188 1 #define DST_TYPE_HAS_TS204 2 #define DST_TYPE_HAS_SYMDIV 4 #define DST_TYPE_HAS_FW_1 8 @@ -52,6 +52,9 @@ #define DST_TYPE_HAS_OBS_REGS 128 #define DST_TYPE_HAS_INC_COUNT 256 #define DST_TYPE_HAS_MULTI_FE 512 +#define DST_TYPE_HAS_NEWTUNE_2 1024 +#define DST_TYPE_HAS_DBOARD 2048 +#define DST_TYPE_HAS_VLF 4096 /* Card capability list */ @@ -64,6 +67,20 @@ #define DST_TYPE_HAS_ANALOG 64 /* Analog inputs */ #define DST_TYPE_HAS_SESSION 128 +#define TUNER_TYPE_MULTI 1 +#define TUNER_TYPE_UNKNOWN 2 +/* DVB-S */ +#define TUNER_TYPE_L64724 4 +#define TUNER_TYPE_STV0299 8 +#define TUNER_TYPE_MB86A15 16 + +/* DVB-T */ +#define TUNER_TYPE_TDA10046 32 + +/* ATSC */ +#define TUNER_TYPE_NXT200x 64 + + #define RDC_8820_PIO_0_DISABLE 0 #define RDC_8820_PIO_0_ENABLE 1 #define RDC_8820_INT 2 @@ -84,8 +101,6 @@ struct dst_state { struct bt878* bt; - struct dvb_frontend_ops ops; - /* configuration settings */ const struct dst_config* config; @@ -121,8 +136,17 @@ struct dst_state { u8 card_info[8]; u8 vendor[8]; u8 board_info[8]; - + u32 tuner_type; + char *tuner_name; struct mutex dst_mutex; + u8 fw_name[8]; +}; + +struct tuner_types { + u32 tuner_type; + char *tuner_name; + char *board_name; + char *fw_name; }; struct dst_types { @@ -131,6 +155,7 @@ struct dst_types { u8 dst_type; u32 type_flags; u32 dst_feature; + u32 tuner_type; }; struct dst_config diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c index ccc7b2eb4a2..b715b972d2f 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c @@ -147,12 +147,15 @@ static int thomson_dtt7579_demod_init(struct dvb_frontend* fe) return 0; } -static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +static int thomson_dtt7579_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) { u32 div; unsigned char bs = 0; unsigned char cp = 0; + if (buf_len < 5) + return -EINVAL; + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; if (params->frequency < 542000000) @@ -169,22 +172,25 @@ static int thomson_dtt7579_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ else bs = 0x08; - pllbuf[0] = 0xc0; // Note: non-linux standard PLL i2c address + pllbuf[0] = 0x60; pllbuf[1] = div >> 8; pllbuf[2] = div & 0xff; pllbuf[3] = cp; pllbuf[4] = bs; - return 0; + return 5; } static struct mt352_config thomson_dtt7579_config = { .demod_address = 0x0f, .demod_init = thomson_dtt7579_demod_init, - .pll_set = thomson_dtt7579_pll_set, }; -static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static struct zl10353_config thomson_dtt7579_zl10353_config = { + .demod_address = 0x0f, +}; + +static int cx24108_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { u32 freq = params->frequency; @@ -237,7 +243,7 @@ static int cx24108_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete return 0; } -static int pinnsat_pll_init(struct dvb_frontend* fe) +static int pinnsat_tuner_init(struct dvb_frontend* fe) { struct dvb_bt8xx_card *card = fe->dvb->priv; @@ -247,7 +253,7 @@ static int pinnsat_pll_init(struct dvb_frontend* fe) return 0; } -static int pinnsat_pll_sleep(struct dvb_frontend* fe) +static int pinnsat_tuner_sleep(struct dvb_frontend* fe) { struct dvb_bt8xx_card *card = fe->dvb->priv; @@ -258,12 +264,9 @@ static int pinnsat_pll_sleep(struct dvb_frontend* fe) static struct cx24110_config pctvsat_config = { .demod_address = 0x55, - .pll_init = pinnsat_pll_init, - .pll_set = cx24108_pll_set, - .pll_sleep = pinnsat_pll_sleep, }; -static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int microtune_mt7202dtf_tuner_set_params(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; @@ -297,6 +300,8 @@ static int microtune_mt7202dtf_pll_set(struct dvb_frontend* fe, struct dvb_front data[2] = ((div >> 10) & 0x60) | cfg; data[3] = (cpump << 6) | band_select; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); i2c_transfer(card->i2c_adapter, &msg, 1); return (div * 166666 - 36000000); } @@ -310,7 +315,6 @@ static int microtune_mt7202dtf_request_firmware(struct dvb_frontend* fe, const s static struct sp887x_config microtune_mt7202dtf_config = { .demod_address = 0x70, - .pll_set = microtune_mt7202dtf_pll_set, .request_firmware = microtune_mt7202dtf_request_firmware, }; @@ -337,12 +341,14 @@ static int advbt771_samsung_tdtc9251dh0_demod_init(struct dvb_frontend* fe) return 0; } -static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +static int advbt771_samsung_tdtc9251dh0_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) { u32 div; unsigned char bs = 0; unsigned char cp = 0; + if (buf_len < 5) return -EINVAL; + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; if (params->frequency < 150000000) @@ -383,19 +389,18 @@ static int advbt771_samsung_tdtc9251dh0_pll_set(struct dvb_frontend* fe, struct else bs = 0x08; - pllbuf[0] = 0xc2; // Note: non-linux standard PLL i2c address + pllbuf[0] = 0x61; pllbuf[1] = div >> 8; pllbuf[2] = div & 0xff; pllbuf[3] = cp; pllbuf[4] = bs; - return 0; + return 5; } 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 = { @@ -455,7 +460,7 @@ static struct or51211_config or51211_config = { .sleep = or51211_sleep, }; -static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int vp3021_alps_tded4_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; u8 buf[4]; @@ -478,6 +483,8 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten else return -EINVAL; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); i2c_transfer(card->i2c_adapter, &msg, 1); return 0; } @@ -485,7 +492,6 @@ static int vp3021_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten static struct nxt6000_config vp3021_alps_tded4_config = { .demod_address = 0x0a, .clock_inversion = 1, - .pll_set = vp3021_alps_tded4_pll_set, }; static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) @@ -506,14 +512,17 @@ static int digitv_alps_tded4_demod_init(struct dvb_frontend* fe) return 0; } -static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf) +static int digitv_alps_tded4_tuner_calc_regs(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf, int buf_len) { u32 div; struct dvb_ofdm_parameters *op = ¶ms->u.ofdm; + if (buf_len < 5) + return -EINVAL; + div = (((params->frequency + 83333) * 3) / 500000) + IF_FREQUENCYx6; - pllbuf[0] = 0xc2; + pllbuf[0] = 0x61; pllbuf[1] = (div >> 8) & 0x7F; pllbuf[2] = div & 0xFF; pllbuf[3] = 0x85; @@ -530,7 +539,7 @@ static int digitv_alps_tded4_pll_set(struct dvb_frontend* fe, struct dvb_fronten if (op->bandwidth == 8) pllbuf[4] |= 0x04; - return 0; + return 5; } static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) @@ -557,43 +566,18 @@ static void digitv_alps_tded4_reset(struct dvb_bt8xx_card *bt) static struct mt352_config digitv_alps_tded4_config = { .demod_address = 0x0a, .demod_init = digitv_alps_tded4_demod_init, - .pll_set = digitv_alps_tded4_pll_set, }; -static int tdvs_tua6034_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int tdvs_tua6034_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct dvb_bt8xx_card *card = (struct dvb_bt8xx_card *) fe->dvb->priv; - u8 buf[4]; - struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = buf, .len = sizeof(buf) }; - int err; - - dvb_pll_configure(&dvb_pll_tdvs_tua6034, buf, params->frequency, 0); - dprintk("%s: tuner at 0x%02x bytes: 0x%02x 0x%02x 0x%02x 0x%02x\n", - __FUNCTION__, msg.addr, buf[0],buf[1],buf[2],buf[3]); - if ((err = i2c_transfer(card->i2c_adapter, &msg, 1)) != 1) { - printk(KERN_WARNING "dvb-bt8xx: %s error " - "(addr %02x <- %02x, err = %i)\n", - __FUNCTION__, buf[0], buf[1], err); - if (err < 0) - return err; - else - return -EREMOTEIO; - } - - /* Set the Auxiliary Byte. */ - buf[2] &= ~0x20; - buf[2] |= 0x18; - buf[3] = 0x50; - i2c_transfer(card->i2c_adapter, &msg, 1); - - return 0; + return lg_h06xf_pll_set(fe, card->i2c_adapter, params); } static struct lgdt330x_config tdvs_tua6034_config = { .demod_address = 0x0e, .demod_chip = LGDT3303, .serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */ - .pll_set = tdvs_tua6034_pll_set, }; static void lgdt330x_reset(struct dvb_bt8xx_card *bt) @@ -617,17 +601,25 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) switch(type) { case BTTV_BOARD_DVICO_DVBT_LITE: card->fe = mt352_attach(&thomson_dtt7579_config, card->i2c_adapter); + + if (card->fe == NULL) + card->fe = zl10353_attach(&thomson_dtt7579_zl10353_config, + card->i2c_adapter); + if (card->fe != NULL) { - card->fe->ops->info.frequency_min = 174000000; - card->fe->ops->info.frequency_max = 862000000; + card->fe->ops.tuner_ops.calc_regs = thomson_dtt7579_tuner_calc_regs; + card->fe->ops.info.frequency_min = 174000000; + card->fe->ops.info.frequency_max = 862000000; } break; case BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE: lgdt330x_reset(card); card->fe = lgdt330x_attach(&tdvs_tua6034_config, card->i2c_adapter); - if (card->fe != NULL) + if (card->fe != NULL) { + card->fe->ops.tuner_ops.set_params = tdvs_tua6034_tuner_set_params; dprintk ("dvb_bt8xx: lgdt330x detected\n"); + } break; case BTTV_BOARD_NEBULA_DIGITV: @@ -640,6 +632,7 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) digitv_alps_tded4_reset(card); card->fe = nxt6000_attach(&vp3021_alps_tded4_config, card->i2c_adapter); if (card->fe != NULL) { + card->fe->ops.tuner_ops.set_params = vp3021_alps_tded4_tuner_set_params; dprintk ("dvb_bt8xx: an nxt6000 was detected on your digitv card\n"); break; } @@ -648,19 +641,25 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) digitv_alps_tded4_reset(card); card->fe = mt352_attach(&digitv_alps_tded4_config, card->i2c_adapter); - if (card->fe != NULL) + if (card->fe != NULL) { + card->fe->ops.tuner_ops.calc_regs = digitv_alps_tded4_tuner_calc_regs; dprintk ("dvb_bt8xx: an mt352 was detected on your digitv card\n"); + } break; case BTTV_BOARD_AVDVBT_761: card->fe = sp887x_attach(µtune_mt7202dtf_config, card->i2c_adapter); + if (card->fe) { + card->fe->ops.tuner_ops.set_params = microtune_mt7202dtf_tuner_set_params; + } break; case BTTV_BOARD_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; + card->fe->ops.tuner_ops.calc_regs = advbt771_samsung_tdtc9251dh0_tuner_calc_regs; + card->fe->ops.info.frequency_min = 174000000; + card->fe->ops.info.frequency_max = 862000000; } break; @@ -687,6 +686,11 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) case BTTV_BOARD_PINNACLESAT: card->fe = cx24110_attach(&pctvsat_config, card->i2c_adapter); + if (card->fe) { + card->fe->ops.tuner_ops.init = pinnsat_tuner_init; + card->fe->ops.tuner_ops.sleep = pinnsat_tuner_sleep; + card->fe->ops.tuner_ops.set_params = cx24108_tuner_set_params; + } break; case BTTV_BOARD_PC_HDTV: @@ -703,8 +707,8 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type) 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); + if (card->fe->ops.release) + card->fe->ops.release(card->fe); card->fe = NULL; } } @@ -713,7 +717,7 @@ static int __devinit dvb_bt8xx_load_card(struct dvb_bt8xx_card *card, u32 type) { int result; - if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE)) < 0) { + if ((result = dvb_register_adapter(&card->dvb_adapter, card->card_name, THIS_MODULE, &card->bt->dev->dev)) < 0) { printk("dvb_bt8xx: dvb_register_adapter failed (errno = %d)\n", result); return result; } diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h index 00dd9fa54c8..4745a9017a1 100644 --- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h +++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h @@ -37,6 +37,8 @@ #include "cx24110.h" #include "or51211.h" #include "lgdt330x.h" +#include "lg_h06xf.h" +#include "zl10353.h" struct dvb_bt8xx_card { struct mutex lock; diff --git a/drivers/media/dvb/cinergyT2/Kconfig b/drivers/media/dvb/cinergyT2/Kconfig index 6018fcdba1e..b5cdd57ec6f 100644 --- a/drivers/media/dvb/cinergyT2/Kconfig +++ b/drivers/media/dvb/cinergyT2/Kconfig @@ -64,7 +64,7 @@ config DVB_CINERGYT2_QUERY_INTERVAL config DVB_CINERGYT2_ENABLE_RC_INPUT_DEVICE bool "Register the onboard IR Remote Control Receiver as Input Device" depends on DVB_CINERGYT2_TUNING - default "yes" + default y help Enable this option if you want to use the onboard Infrared Remote Control Receiver as Linux-Input device. diff --git a/drivers/media/dvb/cinergyT2/cinergyT2.c b/drivers/media/dvb/cinergyT2/cinergyT2.c index 9325d039ea6..1b895360042 100644 --- a/drivers/media/dvb/cinergyT2/cinergyT2.c +++ b/drivers/media/dvb/cinergyT2/cinergyT2.c @@ -544,15 +544,19 @@ static unsigned int cinergyt2_poll (struct file *file, struct poll_table_struct { struct dvb_device *dvbdev = file->private_data; struct cinergyt2 *cinergyt2 = dvbdev->priv; + unsigned int mask = 0; if (cinergyt2->disconnect_pending || mutex_lock_interruptible(&cinergyt2->sem)) return -ERESTARTSYS; poll_wait(file, &cinergyt2->poll_wq, wait); + if (cinergyt2->pending_fe_events != 0) + mask |= (POLLIN | POLLRDNORM | POLLPRI); + mutex_unlock(&cinergyt2->sem); - return (POLLIN | POLLRDNORM | POLLPRI); + return mask; } @@ -902,7 +906,7 @@ static int cinergyt2_probe (struct usb_interface *intf, return -ENOMEM; } - if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE)) < 0) { + if ((err = dvb_register_adapter(&cinergyt2->adapter, DRIVER_NAME, THIS_MODULE, &cinergyt2->udev->dev)) < 0) { kfree(cinergyt2); return err; } diff --git a/drivers/media/dvb/dvb-core/Makefile b/drivers/media/dvb/dvb-core/Makefile index 7adb50c1e8e..11054657fdb 100644 --- a/drivers/media/dvb/dvb-core/Makefile +++ b/drivers/media/dvb/dvb-core/Makefile @@ -2,8 +2,8 @@ # Makefile for the kernel DVB device drivers. # -dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ - dvb_ca_en50221.o dvb_frontend.o \ - dvb_net.o dvb_ringbuffer.o +dvb-core-objs = dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ + dvb_ca_en50221.o dvb_frontend.o \ + dvb_net.o dvb_ringbuffer.o dvb_math.o obj-$(CONFIG_DVB_CORE) += dvb-core.o diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c index 04578df3f24..988499dfddf 100644 --- a/drivers/media/dvb/dvb-core/dmxdev.c +++ b/drivers/media/dvb/dvb-core/dmxdev.c @@ -872,9 +872,6 @@ static int dvb_demux_do_ioctl(struct inode *inode, struct file *file, mutex_unlock(&dmxdevfilter->mutex); break; - case DMX_GET_EVENT: - break; - case DMX_GET_PES_PIDS: if (!dmxdev->demux->get_pes_pids) { ret = -EINVAL; diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c index 00347a75068..2a03bf53cb2 100644 --- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c +++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c @@ -1060,8 +1060,18 @@ static int dvb_ca_en50221_thread(void *data) break; case DVB_CA_SLOTSTATE_VALIDATE: - if (dvb_ca_en50221_parse_attributes(ca, slot) - != 0) { + if (dvb_ca_en50221_parse_attributes(ca, slot) != 0) { + /* we need this extra check for annoying interfaces like the budget-av */ + if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && + (ca->pub->poll_slot_status)) { + int status = ca->pub->poll_slot_status(ca->pub, slot, 0); + if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + } + printk("dvb_ca adapter %d: Invalid PC card inserted :(\n", ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; @@ -1108,6 +1118,17 @@ static int dvb_ca_en50221_thread(void *data) case DVB_CA_SLOTSTATE_LINKINIT: if (dvb_ca_en50221_link_init(ca, slot) != 0) { + /* we need this extra check for annoying interfaces like the budget-av */ + if ((!(ca->flags & DVB_CA_EN50221_FLAG_IRQ_CAMCHANGE)) && + (ca->pub->poll_slot_status)) { + int status = ca->pub->poll_slot_status(ca->pub, slot, 0); + if (!(status & DVB_CA_EN50221_POLL_CAM_PRESENT)) { + ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_NONE; + dvb_ca_en50221_thread_update_delay(ca); + break; + } + } + printk("dvb_ca adapter %d: DVB CAM link initialisation failed :(\n", ca->dvbdev->adapter->num); ca->slot_info[slot].slot_state = DVB_CA_SLOTSTATE_INVALID; dvb_ca_en50221_thread_update_delay(ca); diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c index 83ec5e06c48..fcff5eab21a 100644 --- a/drivers/media/dvb/dvb-core/dvb_demux.c +++ b/drivers/media/dvb/dvb-core/dvb_demux.c @@ -473,7 +473,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) goto bailout; } memcpy(&demux->tsbuf[i], buf, j); - if ((demux->tsbuf[0] == 0x47) | (demux->tsbuf[0] == 0xB8)) { + if ((demux->tsbuf[0] == 0x47) || (demux->tsbuf[0] == 0xB8)) { memcpy(tmppack, demux->tsbuf, 188); if (tmppack[0] == 0xB8) tmppack[0] = 0x47; @@ -484,7 +484,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count) } while (p < count) { - if ((buf[p] == 0x47) | (buf[p] == 0xB8)) { + if ((buf[p] == 0x47) || (buf[p] == 0xB8)) { if (count - p >= 204) { memcpy(tmppack, &buf[p], 188); if (tmppack[0] == 0xB8) diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c index a051790161b..5e8bb41a088 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.c +++ b/drivers/media/dvb/dvb-core/dvb_frontend.c @@ -56,7 +56,7 @@ MODULE_PARM_DESC(dvb_force_auto_inversion, "0: normal (default), 1: INVERSION_AU module_param(dvb_override_tune_delay, int, 0644); MODULE_PARM_DESC(dvb_override_tune_delay, "0: normal (default), >0 => delay in milliseconds to wait for lock after a tune attempt"); module_param(dvb_powerdown_on_sleep, int, 0644); -MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB volatage off on sleep (default)"); +MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB voltage off on sleep (default)"); #define dprintk if (dvb_frontend_debug) printk @@ -72,6 +72,8 @@ MODULE_PARM_DESC(dvb_powerdown_on_sleep, "0: do not power down, 1: turn LNB vola #define FESTATE_SEARCHING_FAST (FESTATE_TUNING_FAST | FESTATE_ZIGZAG_FAST) #define FESTATE_SEARCHING_SLOW (FESTATE_TUNING_SLOW | FESTATE_ZIGZAG_SLOW) #define FESTATE_LOSTLOCK (FESTATE_ZIGZAG_FAST | FESTATE_ZIGZAG_SLOW) + +#define FE_ALGO_HW 1 /* * FESTATE_IDLE. No tuning parameters have been supplied and the loop is idling. * FESTATE_RETUNE. Parameters have been supplied, but we have not yet performed the first tune. @@ -151,8 +153,8 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, fe_status_t status) sizeof (struct dvb_frontend_parameters)); if (status & FE_HAS_LOCK) - if (fe->ops->get_frontend) - fe->ops->get_frontend(fe, &e->parameters); + if (fe->ops.get_frontend) + fe->ops.get_frontend(fe, &e->parameters); events->eventw = wp; @@ -211,10 +213,15 @@ static void dvb_frontend_init(struct dvb_frontend *fe) { dprintk ("DVB: initialising frontend %i (%s)...\n", fe->dvb->num, - fe->ops->info.name); - - if (fe->ops->init) - fe->ops->init(fe); + fe->ops.info.name); + + if (fe->ops.init) + fe->ops.init(fe); + if (fe->ops.tuner_ops.init) { + fe->ops.tuner_ops.init(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } } void dvb_frontend_reinitialise(struct dvb_frontend *fe) @@ -259,7 +266,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra u32 original_frequency = fepriv->parameters.frequency; /* are we using autoinversion? */ - autoinversion = ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) && + autoinversion = ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && (fepriv->parameters.inversion == INVERSION_AUTO)); /* setup parameters correctly */ @@ -329,8 +336,8 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra fepriv->parameters.frequency += fepriv->lnb_drift; if (autoinversion) fepriv->parameters.inversion = fepriv->inversion; - if (fe->ops->set_frontend) - fe->ops->set_frontend(fe, &fepriv->parameters); + if (fe->ops.set_frontend) + fe->ops.set_frontend(fe, &fepriv->parameters); fepriv->parameters.frequency = original_frequency; fepriv->parameters.inversion = original_inversion; @@ -354,8 +361,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) /* in SCAN mode, we just set the frontend when asked and leave it alone */ if (fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT) { if (fepriv->state & FESTATE_RETUNE) { - if (fe->ops->set_frontend) - fe->ops->set_frontend(fe, &fepriv->parameters); + if (fe->ops.set_frontend) + fe->ops.set_frontend(fe, &fepriv->parameters); fepriv->state = FESTATE_TUNED; } fepriv->delay = 3*HZ; @@ -367,8 +374,8 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) if (fepriv->state & FESTATE_RETUNE) { s = 0; } else { - if (fe->ops->read_status) - fe->ops->read_status(fe, &s); + if (fe->ops.read_status) + fe->ops.read_status(fe, &s); if (s != fepriv->status) { dvb_frontend_add_event(fe, s); fepriv->status = s; @@ -381,7 +388,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) fepriv->state = FESTATE_TUNED; /* if we're tuned, then we have determined the correct inversion */ - if ((!(fe->ops->info.caps & FE_CAN_INVERSION_AUTO)) && + if ((!(fe->ops.info.caps & FE_CAN_INVERSION_AUTO)) && (fepriv->parameters.inversion == INVERSION_AUTO)) { fepriv->parameters.inversion = fepriv->inversion; } @@ -405,7 +412,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) /* don't actually do anything if we're in the LOSTLOCK state, * the frontend is set to FE_CAN_RECOVER, and the max_drift is 0 */ if ((fepriv->state & FESTATE_LOSTLOCK) && - (fe->ops->info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { + (fe->ops.info.caps & FE_CAN_RECOVER) && (fepriv->max_drift == 0)) { dvb_frontend_swzigzag_update_delay(fepriv, s & FE_HAS_LOCK); return; } @@ -540,39 +547,45 @@ static int dvb_frontend_thread(void *data) if (fepriv->reinitialise) { dvb_frontend_init(fe); if (fepriv->tone != -1) { - fe->ops->set_tone(fe, fepriv->tone); + fe->ops.set_tone(fe, fepriv->tone); } if (fepriv->voltage != -1) { - fe->ops->set_voltage(fe, fepriv->voltage); + fe->ops.set_voltage(fe, fepriv->voltage); } fepriv->reinitialise = 0; } /* do an iteration of the tuning loop */ - if (fe->ops->tune) { - /* have we been asked to retune? */ - params = NULL; - if (fepriv->state & FESTATE_RETUNE) { - params = &fepriv->parameters; - fepriv->state = FESTATE_TUNED; - } + if (fe->ops.get_frontend_algo) { + if (fe->ops.get_frontend_algo(fe) == FE_ALGO_HW) { + /* have we been asked to retune? */ + params = NULL; + if (fepriv->state & FESTATE_RETUNE) { + params = &fepriv->parameters; + fepriv->state = FESTATE_TUNED; + } - fe->ops->tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); - if (s != fepriv->status) { - dvb_frontend_add_event(fe, s); - fepriv->status = s; + fe->ops.tune(fe, params, fepriv->tune_mode_flags, &fepriv->delay, &s); + if (s != fepriv->status) { + dvb_frontend_add_event(fe, s); + fepriv->status = s; + } } - } else { + } else dvb_frontend_swzigzag(fe); - } } if (dvb_shutdown_timeout) { if (dvb_powerdown_on_sleep) - if (fe->ops->set_voltage) - fe->ops->set_voltage(fe, SEC_VOLTAGE_OFF); - if (fe->ops->sleep) - fe->ops->sleep(fe); + if (fe->ops.set_voltage) + fe->ops.set_voltage(fe, SEC_VOLTAGE_OFF); + if (fe->ops.tuner_ops.sleep) { + fe->ops.tuner_ops.sleep(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + if (fe->ops.sleep) + fe->ops.sleep(fe); } fepriv->thread_pid = 0; @@ -724,7 +737,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, switch (cmd) { case FE_GET_INFO: { struct dvb_frontend_info* info = parg; - memcpy(info, &fe->ops->info, sizeof(struct dvb_frontend_info)); + memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); /* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't * do it, it is done for it. */ @@ -744,58 +757,58 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; } - if (fe->ops->read_status) - err = fe->ops->read_status(fe, status); + if (fe->ops.read_status) + err = fe->ops.read_status(fe, status); break; } case FE_READ_BER: - if (fe->ops->read_ber) - err = fe->ops->read_ber(fe, (__u32*) parg); + if (fe->ops.read_ber) + err = fe->ops.read_ber(fe, (__u32*) parg); break; case FE_READ_SIGNAL_STRENGTH: - if (fe->ops->read_signal_strength) - err = fe->ops->read_signal_strength(fe, (__u16*) parg); + if (fe->ops.read_signal_strength) + err = fe->ops.read_signal_strength(fe, (__u16*) parg); break; case FE_READ_SNR: - if (fe->ops->read_snr) - err = fe->ops->read_snr(fe, (__u16*) parg); + if (fe->ops.read_snr) + err = fe->ops.read_snr(fe, (__u16*) parg); break; case FE_READ_UNCORRECTED_BLOCKS: - if (fe->ops->read_ucblocks) - err = fe->ops->read_ucblocks(fe, (__u32*) parg); + if (fe->ops.read_ucblocks) + err = fe->ops.read_ucblocks(fe, (__u32*) parg); break; case FE_DISEQC_RESET_OVERLOAD: - if (fe->ops->diseqc_reset_overload) { - err = fe->ops->diseqc_reset_overload(fe); + if (fe->ops.diseqc_reset_overload) { + err = fe->ops.diseqc_reset_overload(fe); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } break; case FE_DISEQC_SEND_MASTER_CMD: - if (fe->ops->diseqc_send_master_cmd) { - err = fe->ops->diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg); + if (fe->ops.diseqc_send_master_cmd) { + err = fe->ops.diseqc_send_master_cmd(fe, (struct dvb_diseqc_master_cmd*) parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } break; case FE_DISEQC_SEND_BURST: - if (fe->ops->diseqc_send_burst) { - err = fe->ops->diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg); + if (fe->ops.diseqc_send_burst) { + err = fe->ops.diseqc_send_burst(fe, (fe_sec_mini_cmd_t) parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; } break; case FE_SET_TONE: - if (fe->ops->set_tone) { - err = fe->ops->set_tone(fe, (fe_sec_tone_mode_t) parg); + if (fe->ops.set_tone) { + err = fe->ops.set_tone(fe, (fe_sec_tone_mode_t) parg); fepriv->tone = (fe_sec_tone_mode_t) parg; fepriv->state = FESTATE_DISEQC; fepriv->status = 0; @@ -803,8 +816,8 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; case FE_SET_VOLTAGE: - if (fe->ops->set_voltage) { - err = fe->ops->set_voltage(fe, (fe_sec_voltage_t) parg); + if (fe->ops.set_voltage) { + err = fe->ops.set_voltage(fe, (fe_sec_voltage_t) parg); fepriv->voltage = (fe_sec_voltage_t) parg; fepriv->state = FESTATE_DISEQC; fepriv->status = 0; @@ -812,11 +825,11 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; case FE_DISHNETWORK_SEND_LEGACY_CMD: - if (fe->ops->dishnetwork_send_legacy_command) { - err = fe->ops->dishnetwork_send_legacy_command(fe, (unsigned long) parg); + if (fe->ops.dishnetwork_send_legacy_command) { + err = fe->ops.dishnetwork_send_legacy_command(fe, (unsigned long) parg); fepriv->state = FESTATE_DISEQC; fepriv->status = 0; - } else if (fe->ops->set_voltage) { + } else if (fe->ops.set_voltage) { /* * NOTE: This is a fallback condition. Some frontends * (stv0299 for instance) take longer than 8msec to @@ -846,7 +859,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, /* before sending a command, initialize by sending * a 32ms 18V to the switch */ - fe->ops->set_voltage(fe, SEC_VOLTAGE_18); + fe->ops.set_voltage(fe, SEC_VOLTAGE_18); dvb_frontend_sleep_until(&nexttime, 32000); for (i = 0; i < 9; i++) { @@ -854,7 +867,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, do_gettimeofday(&tv[i + 1]); if ((cmd & 0x01) != last) { /* set voltage to (last ? 13V : 18V) */ - fe->ops->set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); + fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); last = (last) ? 0 : 1; } cmd = cmd >> 1; @@ -874,13 +887,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; case FE_DISEQC_RECV_SLAVE_REPLY: - if (fe->ops->diseqc_recv_slave_reply) - err = fe->ops->diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); + if (fe->ops.diseqc_recv_slave_reply) + err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); break; case FE_ENABLE_HIGH_LNB_VOLTAGE: - if (fe->ops->enable_high_lnb_voltage) - err = fe->ops->enable_high_lnb_voltage(fe, (long) parg); + if (fe->ops.enable_high_lnb_voltage) + err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); break; case FE_SET_FRONTEND: { @@ -898,7 +911,7 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, fepriv->parameters.inversion = INVERSION_AUTO; fetunesettings.parameters.inversion = INVERSION_AUTO; } - if (fe->ops->info.type == FE_OFDM) { + if (fe->ops.info.type == FE_OFDM) { /* without hierachical coding code_rate_LP is irrelevant, * so we tolerate the otherwise invalid FEC_NONE setting */ if (fepriv->parameters.u.ofdm.hierarchy_information == HIERARCHY_NONE && @@ -907,13 +920,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, } /* get frontend-specific tuning settings */ - if (fe->ops->get_tune_settings && (fe->ops->get_tune_settings(fe, &fetunesettings) == 0)) { + if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; fepriv->max_drift = fetunesettings.max_drift; fepriv->step_size = fetunesettings.step_size; } else { /* default values */ - switch(fe->ops->info.type) { + switch(fe->ops.info.type) { case FE_QPSK: fepriv->min_delay = HZ/20; fepriv->step_size = fepriv->parameters.u.qpsk.symbol_rate / 16000; @@ -928,11 +941,13 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, case FE_OFDM: fepriv->min_delay = HZ/20; - fepriv->step_size = fe->ops->info.frequency_stepsize * 2; - fepriv->max_drift = (fe->ops->info.frequency_stepsize * 2) + 1; + fepriv->step_size = fe->ops.info.frequency_stepsize * 2; + fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; break; case FE_ATSC: - printk("dvb-core: FE_ATSC not handled yet.\n"); + fepriv->min_delay = HZ/20; + fepriv->step_size = 0; + fepriv->max_drift = 0; break; } } @@ -952,9 +967,9 @@ static int dvb_frontend_ioctl(struct inode *inode, struct file *file, break; case FE_GET_FRONTEND: - if (fe->ops->get_frontend) { + if (fe->ops.get_frontend) { memcpy (parg, &fepriv->parameters, sizeof (struct dvb_frontend_parameters)); - err = fe->ops->get_frontend(fe, (struct dvb_frontend_parameters*) parg); + err = fe->ops.get_frontend(fe, (struct dvb_frontend_parameters*) parg); } break; @@ -1067,7 +1082,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, printk ("DVB: registering frontend %i (%s)...\n", fe->dvb->num, - fe->ops->info.name); + fe->ops.info.name); dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, fe, DVB_DEVICE_FRONTEND); @@ -1085,10 +1100,15 @@ int dvb_unregister_frontend(struct dvb_frontend* fe) mutex_lock(&frontend_mutex); dvb_unregister_device (fepriv->dvbdev); dvb_frontend_stop (fe); - if (fe->ops->release) - fe->ops->release(fe); + if (fe->ops.tuner_ops.release) { + fe->ops.tuner_ops.release(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + if (fe->ops.release) + fe->ops.release(fe); else - printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops->info.name); + printk("dvb_frontend: Demodulator (%s) does not have a release callback!\n", fe->ops.info.name); /* fe is invalid now */ kfree(fepriv); mutex_unlock(&frontend_mutex); diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h index 5926a3b745c..2887e2b862a 100644 --- a/drivers/media/dvb/dvb-core/dvb_frontend.h +++ b/drivers/media/dvb/dvb-core/dvb_frontend.h @@ -49,6 +49,44 @@ struct dvb_frontend_tune_settings { struct dvb_frontend; +struct dvb_tuner_info { + char name[128]; + + u32 frequency_min; + u32 frequency_max; + u32 frequency_step; + + u32 bandwidth_min; + u32 bandwidth_max; + u32 bandwidth_step; +}; + +struct dvb_tuner_ops { + + struct dvb_tuner_info info; + + int (*release)(struct dvb_frontend *fe); + int (*init)(struct dvb_frontend *fe); + int (*sleep)(struct dvb_frontend *fe); + + /** This is for simple PLLs - set all parameters in one go. */ + int (*set_params)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); + + /** This is support for demods like the mt352 - fills out the supplied buffer with what to write. */ + int (*calc_regs)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p, u8 *buf, int buf_len); + + int (*get_frequency)(struct dvb_frontend *fe, u32 *frequency); + int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth); + +#define TUNER_STATUS_LOCKED 1 + int (*get_status)(struct dvb_frontend *fe, u32 *status); + + /** These are provided seperately from set_params in order to facilitate silicon + * tuners which require sophisticated tuning loops, controlling each parameter seperately. */ + int (*set_frequency)(struct dvb_frontend *fe, u32 frequency); + int (*set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth); +}; + struct dvb_frontend_ops { struct dvb_frontend_info info; @@ -64,6 +102,8 @@ struct dvb_frontend_ops { unsigned int mode_flags, int *delay, fe_status_t *status); + /* get frontend tuning algorithm from the module */ + int (*get_frontend_algo)(struct dvb_frontend *fe); /* these two are only used for the swzigzag code */ int (*set_frontend)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); @@ -86,6 +126,8 @@ struct dvb_frontend_ops { int (*enable_high_lnb_voltage)(struct dvb_frontend* fe, long arg); int (*dishnetwork_send_legacy_command)(struct dvb_frontend* fe, unsigned long cmd); int (*i2c_gate_ctrl)(struct dvb_frontend* fe, int enable); + + struct dvb_tuner_ops tuner_ops; }; #define MAX_EVENT 8 @@ -100,9 +142,10 @@ struct dvb_fe_events { }; struct dvb_frontend { - struct dvb_frontend_ops* ops; + struct dvb_frontend_ops ops; struct dvb_adapter *dvb; void* demodulator_priv; + void* tuner_priv; void* frontend_priv; void* misc_priv; }; diff --git a/drivers/media/dvb/dvb-core/dvb_math.c b/drivers/media/dvb/dvb-core/dvb_math.c new file mode 100644 index 00000000000..beb7c93aa6c --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_math.c @@ -0,0 +1,145 @@ +/* + * dvb-math provides some complex fixed-point math + * operations shared between the dvb related stuff + * + * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <linux/bitops.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <asm/bug.h> +#include "dvb_math.h" + +static const unsigned short logtable[256] = { + 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, + 0x0b5d, 0x0cc3, 0x0e27, 0x0f8a, 0x10eb, 0x124b, 0x13aa, 0x1508, + 0x1664, 0x17bf, 0x1919, 0x1a71, 0x1bc8, 0x1d1e, 0x1e73, 0x1fc6, + 0x2119, 0x226a, 0x23ba, 0x2508, 0x2656, 0x27a2, 0x28ed, 0x2a37, + 0x2b80, 0x2cc8, 0x2e0f, 0x2f54, 0x3098, 0x31dc, 0x331e, 0x345f, + 0x359f, 0x36de, 0x381b, 0x3958, 0x3a94, 0x3bce, 0x3d08, 0x3e41, + 0x3f78, 0x40af, 0x41e4, 0x4319, 0x444c, 0x457f, 0x46b0, 0x47e1, + 0x4910, 0x4a3f, 0x4b6c, 0x4c99, 0x4dc5, 0x4eef, 0x5019, 0x5142, + 0x526a, 0x5391, 0x54b7, 0x55dc, 0x5700, 0x5824, 0x5946, 0x5a68, + 0x5b89, 0x5ca8, 0x5dc7, 0x5ee5, 0x6003, 0x611f, 0x623a, 0x6355, + 0x646f, 0x6588, 0x66a0, 0x67b7, 0x68ce, 0x69e4, 0x6af8, 0x6c0c, + 0x6d20, 0x6e32, 0x6f44, 0x7055, 0x7165, 0x7274, 0x7383, 0x7490, + 0x759d, 0x76aa, 0x77b5, 0x78c0, 0x79ca, 0x7ad3, 0x7bdb, 0x7ce3, + 0x7dea, 0x7ef0, 0x7ff6, 0x80fb, 0x81ff, 0x8302, 0x8405, 0x8507, + 0x8608, 0x8709, 0x8809, 0x8908, 0x8a06, 0x8b04, 0x8c01, 0x8cfe, + 0x8dfa, 0x8ef5, 0x8fef, 0x90e9, 0x91e2, 0x92db, 0x93d2, 0x94ca, + 0x95c0, 0x96b6, 0x97ab, 0x98a0, 0x9994, 0x9a87, 0x9b7a, 0x9c6c, + 0x9d5e, 0x9e4f, 0x9f3f, 0xa02e, 0xa11e, 0xa20c, 0xa2fa, 0xa3e7, + 0xa4d4, 0xa5c0, 0xa6ab, 0xa796, 0xa881, 0xa96a, 0xaa53, 0xab3c, + 0xac24, 0xad0c, 0xadf2, 0xaed9, 0xafbe, 0xb0a4, 0xb188, 0xb26c, + 0xb350, 0xb433, 0xb515, 0xb5f7, 0xb6d9, 0xb7ba, 0xb89a, 0xb97a, + 0xba59, 0xbb38, 0xbc16, 0xbcf4, 0xbdd1, 0xbead, 0xbf8a, 0xc065, + 0xc140, 0xc21b, 0xc2f5, 0xc3cf, 0xc4a8, 0xc580, 0xc658, 0xc730, + 0xc807, 0xc8de, 0xc9b4, 0xca8a, 0xcb5f, 0xcc34, 0xcd08, 0xcddc, + 0xceaf, 0xcf82, 0xd054, 0xd126, 0xd1f7, 0xd2c8, 0xd399, 0xd469, + 0xd538, 0xd607, 0xd6d6, 0xd7a4, 0xd872, 0xd93f, 0xda0c, 0xdad9, + 0xdba5, 0xdc70, 0xdd3b, 0xde06, 0xded0, 0xdf9a, 0xe063, 0xe12c, + 0xe1f5, 0xe2bd, 0xe385, 0xe44c, 0xe513, 0xe5d9, 0xe69f, 0xe765, + 0xe82a, 0xe8ef, 0xe9b3, 0xea77, 0xeb3b, 0xebfe, 0xecc1, 0xed83, + 0xee45, 0xef06, 0xefc8, 0xf088, 0xf149, 0xf209, 0xf2c8, 0xf387, + 0xf446, 0xf505, 0xf5c3, 0xf680, 0xf73e, 0xf7fb, 0xf8b7, 0xf973, + 0xfa2f, 0xfaea, 0xfba5, 0xfc60, 0xfd1a, 0xfdd4, 0xfe8e, 0xff47 +}; + +unsigned int intlog2(u32 value) +{ + /** + * returns: log2(value) * 2^24 + * wrong result if value = 0 (log2(0) is undefined) + */ + unsigned int msb; + unsigned int logentry; + unsigned int significand; + unsigned int interpolation; + + if (unlikely(value == 0)) { + WARN_ON(1); + return 0; + } + + /* first detect the msb (count begins at 0) */ + msb = fls(value) - 1; + + /** + * now we use a logtable after the following method: + * + * log2(2^x * y) * 2^24 = x * 2^24 + log2(y) * 2^24 + * where x = msb and therefore 1 <= y < 2 + * first y is determined by shifting the value left + * so that msb is bit 31 + * 0x00231f56 -> 0x8C7D5800 + * the result is y * 2^31 -> "significand" + * then the highest 9 bits are used for a table lookup + * the highest bit is discarded because it's always set + * the highest nine bits in our example are 100011000 + * so we would use the entry 0x18 + */ + significand = value << (31 - msb); + logentry = (significand >> 23) & 0xff; + + /** + * last step we do is interpolation because of the + * limitations of the log table the error is that part of + * the significand which isn't used for lookup then we + * compute the ratio between the error and the next table entry + * and interpolate it between the log table entry used and the + * next one the biggest error possible is 0x7fffff + * (in our example it's 0x7D5800) + * needed value for next table entry is 0x800000 + * so the interpolation is + * (error / 0x800000) * (logtable_next - logtable_current) + * in the implementation the division is moved to the end for + * better accuracy there is also an overflow correction if + * logtable_next is 256 + */ + interpolation = ((significand & 0x7fffff) * + ((logtable[(logentry + 1) & 0xff] - + logtable[logentry]) & 0xffff)) >> 15; + + /* now we return the result */ + return ((msb << 24) + (logtable[logentry] << 8) + interpolation); +} +EXPORT_SYMBOL(intlog2); + +unsigned int intlog10(u32 value) +{ + /** + * returns: log10(value) * 2^24 + * wrong result if value = 0 (log10(0) is undefined) + */ + u64 log; + + if (unlikely(value == 0)) { + WARN_ON(1); + return 0; + } + + log = intlog2(value); + + /** + * we use the following method: + * log10(x) = log2(x) * log10(2) + */ + + return (log * 646456993) >> 31; +} +EXPORT_SYMBOL(intlog10); diff --git a/drivers/media/dvb/dvb-core/dvb_math.h b/drivers/media/dvb/dvb-core/dvb_math.h new file mode 100644 index 00000000000..aecc867e940 --- /dev/null +++ b/drivers/media/dvb/dvb-core/dvb_math.h @@ -0,0 +1,58 @@ +/* + * dvb-math provides some complex fixed-point math + * operations shared between the dvb related stuff + * + * Copyright (C) 2006 Christoph Pfister (christophpfister@gmail.com) + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef __DVB_MATH_H +#define __DVB_MATH_H + +#include <linux/types.h> + +/** + * computes log2 of a value; the result is shifted left by 24 bits + * + * to use rational values you can use the following method: + * intlog2(value) = intlog2(value * 2^x) - x * 2^24 + * + * example: intlog2(8) will give 3 << 24 = 3 * 2^24 + * example: intlog2(9) will give 3 << 24 + ... = 3.16... * 2^24 + * example: intlog2(1.5) = intlog2(3) - 2^24 = 0.584... * 2^24 + * + * @param value The value (must be != 0) + * @return log2(value) * 2^24 + */ +extern unsigned int intlog2(u32 value); + +/** + * computes log10 of a value; the result is shifted left by 24 bits + * + * to use rational values you can use the following method: + * intlog10(value) = intlog10(value * 10^x) - x * 2^24 + * + * example: intlog10(1000) will give 3 << 24 = 3 * 2^24 + * due to the implementation intlog10(1000) might be not exactly 3 * 2^24 + * + * look at intlog2 for similar examples + * + * @param value The value (must be != 0) + * @return log10(value) * 2^24 + */ +extern unsigned int intlog10(u32 value); + +#endif diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c index 9fd87521a16..8859ab74f0f 100644 --- a/drivers/media/dvb/dvb-core/dvb_net.c +++ b/drivers/media/dvb/dvb-core/dvb_net.c @@ -12,7 +12,7 @@ * Hilmar Linder <hlinder@cosy.sbg.ac.at> * and Wolfram Stering <wstering@cosy.sbg.ac.at> * - * ULE Decaps according to draft-ietf-ipdvb-ule-03.txt. + * ULE Decaps according to RFC 4326. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -42,6 +42,9 @@ * Bugfixes and robustness improvements. * Filtering on dest MAC addresses, if present (D-Bit = 0) * ULE_DEBUG compile-time option. + * Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by + * Christian Praehauser <cpraehaus@cosy.sbg.ac.at>, + * Paris Lodron University of Salzburg. */ /* @@ -49,9 +52,6 @@ * * Unloading does not work for 2.6.9 kernels: a refcount doesn't go to zero. * - * TS_FEED callback is called once for every single TS cell although it is - * registered (in dvb_net_feed_start()) for 100 TS cells (used for dvb_net_ule()). - * */ #include <linux/module.h> @@ -89,6 +89,9 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt ) #ifdef ULE_DEBUG +#define MAC_ADDR_PRINTFMT "%.2x:%.2x:%.2x:%.2x:%.2x:%.2x" +#define MAX_ADDR_PRINTFMT_ARGS(macap) (macap)[0],(macap)[1],(macap)[2],(macap)[3],(macap)[4],(macap)[5] + #define isprint(c) ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9')) static void hexdump( const unsigned char *buf, unsigned short len ) @@ -214,6 +217,8 @@ static unsigned short dvb_net_eth_type_trans(struct sk_buff *skb, #define ULE_TEST 0 #define ULE_BRIDGED 1 +#define ULE_OPTEXTHDR_PADDING 0 + static int ule_test_sndu( struct dvb_net_priv *p ) { return -1; @@ -221,14 +226,28 @@ static int ule_test_sndu( struct dvb_net_priv *p ) static int ule_bridged_sndu( struct dvb_net_priv *p ) { - /* BRIDGE SNDU handling sucks in draft-ietf-ipdvb-ule-03.txt. - * This has to be the last extension header, otherwise it won't work. - * Blame the authors! + struct ethhdr *hdr = (struct ethhdr*) p->ule_next_hdr; + if(ntohs(hdr->h_proto) < 1536) { + int framelen = p->ule_sndu_len - ((p->ule_next_hdr+sizeof(struct ethhdr)) - p->ule_skb->data); + /* A frame Type < 1536 for a bridged frame, introduces a LLC Length field. */ + if(framelen != ntohs(hdr->h_proto)) { + return -1; + } + } + /* Note: + * From RFC4326: + * "A bridged SNDU is a Mandatory Extension Header of Type 1. + * It must be the final (or only) extension header specified in the header chain of a SNDU." + * The 'ule_bridged' flag will cause the extension header processing loop to terminate. */ p->ule_bridged = 1; return 0; } +static int ule_exthdr_padding(struct dvb_net_priv *p) +{ + return 0; +} /** Handle ULE extension headers. * Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding. @@ -242,7 +261,8 @@ static int handle_one_ule_extension( struct dvb_net_priv *p ) { [0] = ule_test_sndu, [1] = ule_bridged_sndu, [2] = NULL, }; /* Table of optional extension header handlers. The header type is the index. */ - static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = { NULL, }; + static int (*ule_optional_ext_handlers[255])( struct dvb_net_priv *p ) = + { [0] = ule_exthdr_padding, [1] = NULL, }; int ext_len = 0; unsigned char hlen = (p->ule_sndu_type & 0x0700) >> 8; @@ -253,25 +273,31 @@ static int handle_one_ule_extension( struct dvb_net_priv *p ) /* Mandatory extension header */ if (ule_mandatory_ext_handlers[htype]) { ext_len = ule_mandatory_ext_handlers[htype]( p ); - p->ule_next_hdr += ext_len; - if (! p->ule_bridged) { - p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr ); - p->ule_next_hdr += 2; - } else { - p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN)) ); - /* This assures the extension handling loop will terminate. */ + if(ext_len >= 0) { + p->ule_next_hdr += ext_len; + if (!p->ule_bridged) { + p->ule_sndu_type = ntohs(*(unsigned short *)p->ule_next_hdr); + p->ule_next_hdr += 2; + } else { + p->ule_sndu_type = ntohs(*(unsigned short *)(p->ule_next_hdr + ((p->ule_dbit ? 2 : 3) * ETH_ALEN))); + /* This assures the extension handling loop will terminate. */ + } } + // else: extension handler failed or SNDU should be discarded } else ext_len = -1; /* SNDU has to be discarded. */ } else { /* Optional extension header. Calculate the length. */ - ext_len = hlen << 2; + ext_len = hlen << 1; /* Process the optional extension header according to its type. */ if (ule_optional_ext_handlers[htype]) (void)ule_optional_ext_handlers[htype]( p ); p->ule_next_hdr += ext_len; - p->ule_sndu_type = ntohs( *(unsigned short *)p->ule_next_hdr ); - p->ule_next_hdr += 2; + p->ule_sndu_type = ntohs( *(unsigned short *)(p->ule_next_hdr-2) ); + /* + * note: the length of the next header type is included in the + * length of THIS optional extension header + */ } return ext_len; @@ -284,8 +310,14 @@ static int handle_ule_extensions( struct dvb_net_priv *p ) p->ule_next_hdr = p->ule_skb->data; do { l = handle_one_ule_extension( p ); - if (l == -1) return -1; /* Stop extension header processing and discard SNDU. */ + if (l < 0) + return l; /* Stop extension header processing and discard SNDU. */ total_ext_len += l; +#ifdef ULE_DEBUG + dprintk("handle_ule_extensions: ule_next_hdr=%p, ule_sndu_type=%i, " + "l=%i, total_ext_len=%i\n", p->ule_next_hdr, + (int) p->ule_sndu_type, l, total_ext_len); +#endif } while (p->ule_sndu_type < 1536); @@ -355,8 +387,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); /* Prepare for next SNDU. */ - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++; + priv->stats.rx_errors++; + priv->stats.rx_frame_errors++; } reset_ule(priv); priv->need_pusi = 1; @@ -396,27 +428,25 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) } } - /* Check continuity counter. */ if (new_ts) { + /* Check continuity counter. */ if ((ts[3] & 0x0F) == priv->tscc) priv->tscc = (priv->tscc + 1) & 0x0F; else { /* TS discontinuity handling: */ printk(KERN_WARNING "%lu: TS discontinuity: got %#x, " - "exptected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc); + "expected %#x.\n", priv->ts_count, ts[3] & 0x0F, priv->tscc); /* Drop partly decoded SNDU, reset state, resync on PUSI. */ if (priv->ule_skb) { dev_kfree_skb( priv->ule_skb ); /* Prepare for next SNDU. */ // reset_ule(priv); moved to below. - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_frame_errors++; + priv->stats.rx_errors++; + priv->stats.rx_frame_errors++; } reset_ule(priv); /* skip to next PUSI. */ priv->need_pusi = 1; - ts += TS_SZ; - priv->ts_count++; continue; } /* If we still have an incomplete payload, but PUSI is @@ -425,7 +455,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) * cells (continuity counter wrap). */ if (ts[1] & TS_PUSI) { if (! priv->need_pusi) { - if (*from_where > 181) { + if (!(*from_where < (ts_remain-1)) || *from_where != priv->ule_sndu_remain) { /* Pointer field is invalid. Drop this TS cell and any started ULE SNDU. */ printk(KERN_WARNING "%lu: Invalid pointer " "field: %u.\n", priv->ts_count, *from_where); @@ -438,8 +468,6 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) } reset_ule(priv); priv->need_pusi = 1; - ts += TS_SZ; - priv->ts_count++; continue; } /* Skip pointer field (we're processing a @@ -452,8 +480,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) if (priv->ule_sndu_remain > 183) { /* Current SNDU lacks more data than there could be available in the * current TS cell. */ - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_length_errors++; + priv->stats.rx_errors++; + priv->stats.rx_length_errors++; printk(KERN_WARNING "%lu: Expected %d more SNDU bytes, but " "got PUSI (pf %d, ts_remain %d). Flushing incomplete payload.\n", priv->ts_count, priv->ule_sndu_remain, ts[4], ts_remain); @@ -492,9 +520,11 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) } else priv->ule_dbit = 0; - if (priv->ule_sndu_len > 32763) { + if (priv->ule_sndu_len < 5) { printk(KERN_WARNING "%lu: Invalid ULE SNDU length %u. " "Resyncing.\n", priv->ts_count, priv->ule_sndu_len); + priv->stats.rx_errors++; + priv->stats.rx_length_errors++; priv->ule_sndu_len = 0; priv->need_pusi = 1; new_ts = 1; @@ -608,58 +638,103 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) ule_dump = 1; #endif - ((struct dvb_net_priv *) dev->priv)->stats.rx_errors++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_crc_errors++; + priv->stats.rx_errors++; + priv->stats.rx_crc_errors++; dev_kfree_skb(priv->ule_skb); } else { /* CRC32 verified OK. */ + u8 dest_addr[ETH_ALEN]; + static const u8 bc_addr[ETH_ALEN] = + { [ 0 ... ETH_ALEN-1] = 0xff }; + + /* CRC32 was OK. Remove it from skb. */ + priv->ule_skb->tail -= 4; + priv->ule_skb->len -= 4; + + if (!priv->ule_dbit) { + /* + * The destination MAC address is the + * next data in the skb. It comes + * before any extension headers. + * + * Check if the payload of this SNDU + * should be passed up the stack. + */ + register int drop = 0; + if (priv->rx_mode != RX_MODE_PROMISC) { + if (priv->ule_skb->data[0] & 0x01) { + /* multicast or broadcast */ + if (memcmp(priv->ule_skb->data, bc_addr, ETH_ALEN)) { + /* multicast */ + if (priv->rx_mode == RX_MODE_MULTI) { + int i; + for(i = 0; i < priv->multi_num && memcmp(priv->ule_skb->data, priv->multi_macs[i], ETH_ALEN); i++) + ; + if (i == priv->multi_num) + drop = 1; + } else if (priv->rx_mode != RX_MODE_ALL_MULTI) + drop = 1; /* no broadcast; */ + /* else: all multicast mode: accept all multicast packets */ + } + /* else: broadcast */ + } + else if (memcmp(priv->ule_skb->data, dev->dev_addr, ETH_ALEN)) + drop = 1; + /* else: destination address matches the MAC address of our receiver device */ + } + /* else: promiscious mode; pass everything up the stack */ + + if (drop) { +#ifdef ULE_DEBUG + dprintk("Dropping SNDU: MAC destination address does not match: dest addr: "MAC_ADDR_PRINTFMT", dev addr: "MAC_ADDR_PRINTFMT"\n", + MAX_ADDR_PRINTFMT_ARGS(priv->ule_skb->data), MAX_ADDR_PRINTFMT_ARGS(dev->dev_addr)); +#endif + dev_kfree_skb(priv->ule_skb); + goto sndu_done; + } + else + { + memcpy(dest_addr, priv->ule_skb->data, ETH_ALEN); + skb_pull(priv->ule_skb, ETH_ALEN); + } + } + /* Handle ULE Extension Headers. */ if (priv->ule_sndu_type < 1536) { /* There is an extension header. Handle it accordingly. */ - int l = handle_ule_extensions( priv ); + int l = handle_ule_extensions(priv); if (l < 0) { /* Mandatory extension header unknown or TEST SNDU. Drop it. */ // printk( KERN_WARNING "Dropping SNDU, extension headers.\n" ); - dev_kfree_skb( priv->ule_skb ); + dev_kfree_skb(priv->ule_skb); goto sndu_done; } - skb_pull( priv->ule_skb, l ); + skb_pull(priv->ule_skb, l); } - /* CRC32 was OK. Remove it from skb. */ - priv->ule_skb->tail -= 4; - priv->ule_skb->len -= 4; - - /* Filter on receiver's destination MAC address, if present. */ - if (!priv->ule_dbit) { - /* The destination MAC address is the next data in the skb. */ - if (memcmp( priv->ule_skb->data, dev->dev_addr, ETH_ALEN )) { - /* MAC addresses don't match. Drop SNDU. */ - // printk( KERN_WARNING "Dropping SNDU, MAC address.\n" ); - dev_kfree_skb( priv->ule_skb ); - goto sndu_done; - } - if (! priv->ule_bridged) { - skb_push( priv->ule_skb, ETH_ALEN + 2 ); - ethh = (struct ethhdr *)priv->ule_skb->data; - memcpy( ethh->h_dest, ethh->h_source, ETH_ALEN ); - memset( ethh->h_source, 0, ETH_ALEN ); - ethh->h_proto = htons( priv->ule_sndu_type ); - } else { - /* Skip the Receiver destination MAC address. */ - skb_pull( priv->ule_skb, ETH_ALEN ); - } - } else { - if (! priv->ule_bridged) { - skb_push( priv->ule_skb, ETH_HLEN ); - ethh = (struct ethhdr *)priv->ule_skb->data; - memcpy( ethh->h_dest, dev->dev_addr, ETH_ALEN ); - memset( ethh->h_source, 0, ETH_ALEN ); - ethh->h_proto = htons( priv->ule_sndu_type ); - } else { - /* skb is in correct state; nothing to do. */ + /* + * Construct/assure correct ethernet header. + * Note: in bridged mode (priv->ule_bridged != + * 0) we already have the (original) ethernet + * header at the start of the payload (after + * optional dest. address and any extension + * headers). + */ + + if (!priv->ule_bridged) { + skb_push(priv->ule_skb, ETH_HLEN); + ethh = (struct ethhdr *)priv->ule_skb->data; + if (!priv->ule_dbit) { + /* dest_addr buffer is only valid if priv->ule_dbit == 0 */ + memcpy(ethh->h_dest, dest_addr, ETH_ALEN); + memset(ethh->h_source, 0, ETH_ALEN); } + else /* zeroize source and dest */ + memset( ethh, 0, ETH_ALEN*2 ); + + ethh->h_proto = htons(priv->ule_sndu_type); } + /* else: skb is in correct state; nothing to do. */ priv->ule_bridged = 0; /* Stuff into kernel's protocol stack. */ @@ -668,8 +743,8 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len ) * receive the packet anyhow. */ /* if (priv->ule_dbit && skb->pkt_type == PACKET_OTHERHOST) priv->ule_skb->pkt_type = PACKET_HOST; */ - ((struct dvb_net_priv *) dev->priv)->stats.rx_packets++; - ((struct dvb_net_priv *) dev->priv)->stats.rx_bytes += priv->ule_skb->len; + priv->stats.rx_packets++; + priv->stats.rx_bytes += priv->ule_skb->len; netif_rx(priv->ule_skb); } sndu_done: @@ -944,7 +1019,7 @@ static int dvb_net_feed_start(struct net_device *dev) dprintk("%s: start filtering\n", __FUNCTION__); priv->secfeed->start_filtering(priv->secfeed); } else if (priv->feedtype == DVB_NET_FEEDTYPE_ULE) { - struct timespec timeout = { 0, 30000000 }; // 30 msec + struct timespec timeout = { 0, 10000000 }; // 10 msec /* we have payloads encapsulated in TS */ dprintk("%s: alloc tsfeed\n", __FUNCTION__); @@ -956,10 +1031,13 @@ static int dvb_net_feed_start(struct net_device *dev) /* Set netdevice pointer for ts decaps callback. */ priv->tsfeed->priv = (void *)dev; - ret = priv->tsfeed->set(priv->tsfeed, priv->pid, - TS_PACKET, DMX_TS_PES_OTHER, + ret = priv->tsfeed->set(priv->tsfeed, + priv->pid, /* pid */ + TS_PACKET, /* type */ + DMX_TS_PES_OTHER, /* pes type */ 32768, /* circular buffer size */ - timeout); + timeout /* timeout */ + ); if (ret < 0) { printk("%s: could not set ts feed\n", dev->name); diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c index 3852430d026..134c2bbbeeb 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.c +++ b/drivers/media/dvb/dvb-core/dvbdev.c @@ -236,7 +236,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, "dvb/adapter%d/%s%d", adap->num, dnames[type], id); class_device_create(dvb_class, NULL, MKDEV(DVB_MAJOR, nums2minor(adap->num, type, id)), - NULL, "dvb%d.%s%d", adap->num, dnames[type], id); + adap->device, "dvb%d.%s%d", adap->num, dnames[type], id); dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", adap->num, dnames[type], id, nums2minor(adap->num, type, id), @@ -285,7 +285,7 @@ skip: } -int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module) +int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct module *module, struct device *device) { int num; @@ -306,6 +306,7 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, struct modu adap->num = num; adap->name = name; adap->module = module; + adap->device = device; list_add_tail (&adap->list_head, &dvb_adapter_list); diff --git a/drivers/media/dvb/dvb-core/dvbdev.h b/drivers/media/dvb/dvb-core/dvbdev.h index 74ed5853f0f..d7a976d040d 100644 --- a/drivers/media/dvb/dvb-core/dvbdev.h +++ b/drivers/media/dvb/dvb-core/dvbdev.h @@ -51,6 +51,8 @@ struct dvb_adapter { u8 proposed_mac [6]; void* priv; + struct device *device; + struct module *module; }; @@ -76,7 +78,7 @@ struct dvb_device { }; -extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module); +extern int dvb_register_adapter (struct dvb_adapter *adap, const char *name, struct module *module, struct device *device); extern int dvb_unregister_adapter (struct dvb_adapter *adap); extern int dvb_register_device (struct dvb_adapter *adap, diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig index e388fb1567d..3bc6722a644 100644 --- a/drivers/media/dvb/dvb-usb/Kconfig +++ b/drivers/media/dvb/dvb-usb/Kconfig @@ -88,6 +88,7 @@ config DVB_USB_CXUSB select DVB_CX22702 select DVB_LGDT330X select DVB_MT352 + select DVB_ZL10353 help Say Y here to support the Conexant USB2.0 hybrid reference design. Currently, only DVB and ATSC modes are supported, analog mode @@ -130,6 +131,15 @@ config DVB_USB_VP702X DVB-S USB2.0 receivers. +config DVB_USB_GP8PSK + tristate "GENPIX 8PSK->USB module support" + depends on DVB_USB + help + Say Y here to support the + GENPIX 8psk module + + DVB-S USB2.0 receivers. + config DVB_USB_NOVA_T_USB2 tristate "Hauppauge WinTV-NOVA-T usb2 DVB-T USB2.0 support" depends on DVB_USB diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile index 2dc9aad9681..9643f56c7fe 100644 --- a/drivers/media/dvb/dvb-usb/Makefile +++ b/drivers/media/dvb/dvb-usb/Makefile @@ -7,6 +7,9 @@ obj-$(CONFIG_DVB_USB_VP7045) += dvb-usb-vp7045.o dvb-usb-vp702x-objs = vp702x.o vp702x-fe.o obj-$(CONFIG_DVB_USB_VP702X) += dvb-usb-vp702x.o +dvb-usb-gp8psk-objs = gp8psk.o gp8psk-fe.o +obj-$(CONFIG_DVB_USB_GP8PSK) += dvb-usb-gp8psk.o + dvb-usb-dtt200u-objs = dtt200u.o dtt200u-fe.o obj-$(CONFIG_DVB_USB_DTT200U) += dvb-usb-dtt200u.o diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c index 1f0d3e995c8..ae23bdde42a 100644 --- a/drivers/media/dvb/dvb-usb/cxusb.c +++ b/drivers/media/dvb/dvb-usb/cxusb.c @@ -27,8 +27,10 @@ #include "cx22702.h" #include "lgdt330x.h" +#include "lg_h06xf.h" #include "mt352.h" #include "mt352_priv.h" +#include "zl10353.h" /* debug */ int dvb_usb_cxusb_debug; @@ -322,32 +324,37 @@ static int cxusb_mt352_demod_init(struct dvb_frontend* fe) return 0; } +static int cxusb_lgh064f_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *fep) +{ + struct dvb_usb_device *d = fe->dvb->priv; + return lg_h06xf_pll_set(fe, &d->i2c_adap, fep); +} + static struct cx22702_config cxusb_cx22702_config = { .demod_address = 0x63, .output_mode = CX22702_PARALLEL_OUTPUT, - - .pll_init = dvb_usb_pll_init_i2c, - .pll_set = dvb_usb_pll_set_i2c, }; static struct lgdt330x_config cxusb_lgdt3303_config = { .demod_address = 0x0e, .demod_chip = LGDT3303, - .pll_set = dvb_usb_pll_set_i2c, }; static struct mt352_config cxusb_dee1601_config = { .demod_address = 0x0f, .demod_init = cxusb_dee1601_demod_init, - .pll_set = dvb_usb_pll_set, }; -struct mt352_config cxusb_mt352_config = { +static struct zl10353_config cxusb_zl10353_dee1601_config = { + .demod_address = 0x0f, +}; + +static struct mt352_config cxusb_mt352_config = { /* used in both lgz201 and th7579 */ .demod_address = 0x0f, .demod_init = cxusb_mt352_demod_init, - .pll_set = dvb_usb_pll_set, }; /* Callbacks for DVB USB */ @@ -357,17 +364,10 @@ static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_device *d) d->pll_addr = 0x61; memcpy(d->pll_init, bpll, 4); d->pll_desc = &dvb_pll_fmd1216me; - return 0; -} -static int cxusb_lgh064f_tuner_attach(struct dvb_usb_device *d) -{ - u8 bpll[4] = { 0x00, 0x00, 0x18, 0x50 }; - /* bpll[2] : unset bit 3, set bits 4&5 - bpll[3] : 0x50 - digital, 0x20 - analog */ - d->pll_addr = 0x61; - memcpy(d->pll_init, bpll, 4); - d->pll_desc = &dvb_pll_tdvs_tua6034; + d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; + d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; + return 0; } @@ -375,6 +375,7 @@ static int cxusb_dee1601_tuner_attach(struct dvb_usb_device *d) { d->pll_addr = 0x61; d->pll_desc = &dvb_pll_thomson_dtt7579; + d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; return 0; } @@ -382,6 +383,7 @@ static int cxusb_lgz201_tuner_attach(struct dvb_usb_device *d) { d->pll_addr = 0x61; d->pll_desc = &dvb_pll_lg_z201; + d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; return 0; } @@ -389,6 +391,13 @@ static int cxusb_dtt7579_tuner_attach(struct dvb_usb_device *d) { d->pll_addr = 0x60; d->pll_desc = &dvb_pll_thomson_dtt7579; + d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; + return 0; +} + +static int cxusb_lgdt3303_tuner_attach(struct dvb_usb_device *d) +{ + d->fe->ops.tuner_ops.set_params = cxusb_lgh064f_tuner_set_params; return 0; } @@ -439,7 +448,8 @@ static int cxusb_dee1601_frontend_attach(struct dvb_usb_device *d) cxusb_ctrl_msg(d,CMD_DIGITAL, NULL, 0, NULL, 0); - if ((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) + if (((d->fe = mt352_attach(&cxusb_dee1601_config, &d->i2c_adap)) != NULL) || + ((d->fe = zl10353_attach(&cxusb_zl10353_dee1601_config, &d->i2c_adap)) != NULL)) return 0; return -EIO; @@ -555,7 +565,7 @@ static struct dvb_usb_properties cxusb_bluebird_lgh064f_properties = { .streaming_ctrl = cxusb_streaming_ctrl, .power_ctrl = cxusb_bluebird_power_ctrl, .frontend_attach = cxusb_lgdt3303_frontend_attach, - .tuner_attach = cxusb_lgh064f_tuner_attach, + .tuner_attach = cxusb_lgdt3303_tuner_attach, .i2c_algo = &cxusb_i2c_algo, diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c index 2d52b76671d..abd75b4a350 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-common.c +++ b/drivers/media/dvb/dvb-usb/dibusb-common.c @@ -173,11 +173,10 @@ int dibusb_dib3000mc_frontend_attach(struct dvb_usb_device *d) struct dib3000_config demod_cfg; struct dibusb_state *st = d->priv; - demod_cfg.pll_set = dvb_usb_pll_set_i2c; - demod_cfg.pll_init = dvb_usb_pll_init_i2c; - for (demod_cfg.demod_address = 0x8; demod_cfg.demod_address < 0xd; demod_cfg.demod_address++) if ((d->fe = dib3000mc_attach(&demod_cfg,&d->i2c_adap,&st->ops)) != NULL) { + d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; + d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl; return 0; } @@ -190,6 +189,10 @@ int dibusb_dib3000mc_tuner_attach (struct dvb_usb_device *d) { d->pll_addr = 0x60; d->pll_desc = &dvb_pll_env57h1xd5; + + d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; + d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; + return 0; } EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach); diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c index dd5a1319588..f4c45f386eb 100644 --- a/drivers/media/dvb/dvb-usb/dibusb-mb.c +++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c @@ -20,11 +20,12 @@ static int dibusb_dib3000mb_frontend_attach(struct dvb_usb_device *d) struct dibusb_state *st = d->priv; demod_cfg.demod_address = 0x8; - demod_cfg.pll_set = dvb_usb_pll_set_i2c; - demod_cfg.pll_init = dvb_usb_pll_init_i2c; - if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) + if ((d->fe = dib3000mb_attach(&demod_cfg,&d->i2c_adap,&st->ops)) == NULL) { + d->fe->ops.tuner_ops.init = dvb_usb_tuner_init_i2c; + d->fe->ops.tuner_ops.set_params = dvb_usb_tuner_set_params_i2c; return -ENODEV; + } d->tuner_pass_ctrl = st->ops.tuner_pass_ctrl; diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c index 91136c00ce9..c14d9efb48f 100644 --- a/drivers/media/dvb/dvb-usb/digitv.c +++ b/drivers/media/dvb/dvb-usb/digitv.c @@ -112,27 +112,30 @@ static int digitv_mt352_demod_init(struct dvb_frontend *fe) static struct mt352_config digitv_mt352_config = { .demod_init = digitv_mt352_demod_init, - .pll_set = dvb_usb_pll_set, }; -static int digitv_nxt6000_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +static int digitv_nxt6000_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) { struct dvb_usb_device *d = fe->dvb->priv; u8 b[5]; - dvb_usb_pll_set(fe,fep,b); + dvb_usb_tuner_calc_regs(fe,fep,b, 5); return digitv_ctrl_msg(d,USB_WRITE_TUNER,0,&b[1],4,NULL,0); } static struct nxt6000_config digitv_nxt6000_config = { .clock_inversion = 1, - .pll_set = digitv_nxt6000_pll_set, }; static int digitv_frontend_attach(struct dvb_usb_device *d) { - if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL || - (d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) + if ((d->fe = mt352_attach(&digitv_mt352_config, &d->i2c_adap)) != NULL) { + d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; return 0; + } + if ((d->fe = nxt6000_attach(&digitv_nxt6000_config, &d->i2c_adap)) != NULL) { + d->fe->ops.tuner_ops.set_params = digitv_nxt6000_tuner_set_params; + return 0; + } return -EIO; } diff --git a/drivers/media/dvb/dvb-usb/dtt200u-fe.c b/drivers/media/dvb/dvb-usb/dtt200u-fe.c index cd21ddbfd05..17413adec7a 100644 --- a/drivers/media/dvb/dvb-usb/dtt200u-fe.c +++ b/drivers/media/dvb/dvb-usb/dtt200u-fe.c @@ -18,7 +18,6 @@ struct dtt200u_fe_state { struct dvb_frontend_parameters fep; struct dvb_frontend frontend; - struct dvb_frontend_ops ops; }; static int dtt200u_fe_read_status(struct dvb_frontend* fe, fe_status_t *stat) @@ -163,16 +162,13 @@ struct dvb_frontend* dtt200u_fe_attach(struct dvb_usb_device *d) deb_info("attaching frontend dtt200u\n"); state->d = d; - memcpy(&state->ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops)); - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops,&dtt200u_fe_ops,sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; - goto success; + return &state->frontend; error: return NULL; -success: - return &state->frontend; } static struct dvb_frontend_ops dtt200u_fe_ops = { diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c index 6fa92100248..ec631708c39 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-dvb.c @@ -82,7 +82,7 @@ int dvb_usb_dvb_init(struct dvb_usb_device *d) int ret; if ((ret = dvb_register_adapter(&d->dvb_adap, d->desc->name, - d->owner)) < 0) { + d->owner, &d->udev->dev)) < 0) { deb_info("dvb_register_adapter failed: error %d", ret); goto err; } @@ -121,16 +121,15 @@ int dvb_usb_dvb_init(struct dvb_usb_device *d) dvb_net_init(&d->dvb_adap, &d->dvb_net, &d->demux.dmx); - goto success; + d->state |= DVB_USB_STATE_DVB; + return 0; + err_dmx_dev: dvb_dmx_release(&d->demux); err_dmx: dvb_unregister_adapter(&d->dvb_adap); err: return ret; -success: - d->state |= DVB_USB_STATE_DVB; - return 0; } int dvb_usb_dvb_exit(struct dvb_usb_device *d) @@ -184,13 +183,13 @@ int dvb_usb_fe_init(struct dvb_usb_device* d) /* re-assign sleep and wakeup functions */ if (d->fe != NULL) { - d->fe_init = d->fe->ops->init; d->fe->ops->init = dvb_usb_fe_wakeup; - d->fe_sleep = d->fe->ops->sleep; d->fe->ops->sleep = dvb_usb_fe_sleep; + d->fe_init = d->fe->ops.init; d->fe->ops.init = dvb_usb_fe_wakeup; + d->fe_sleep = d->fe->ops.sleep; d->fe->ops.sleep = dvb_usb_fe_sleep; if (dvb_register_frontend(&d->dvb_adap, d->fe)) { err("Frontend registration failed."); - if (d->fe->ops->release) - d->fe->ops->release(d->fe); + if (d->fe->ops.release) + d->fe->ops.release(d->fe); d->fe = NULL; return -ENODEV; } diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c index 9b254532af4..6b611a72509 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c +++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c @@ -46,7 +46,7 @@ int dvb_usb_i2c_exit(struct dvb_usb_device *d) return 0; } -int dvb_usb_pll_init_i2c(struct dvb_frontend *fe) +int dvb_usb_tuner_init_i2c(struct dvb_frontend *fe) { struct dvb_usb_device *d = fe->dvb->priv; struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = d->pll_init, .len = 4 }; @@ -63,6 +63,8 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe) deb_pll("pll-buf: %x %x %x %x\n",d->pll_init[0],d->pll_init[1], d->pll_init[2],d->pll_init[3]); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) { err("tuner i2c write failed for pll_init."); ret = -EREMOTEIO; @@ -73,38 +75,42 @@ int dvb_usb_pll_init_i2c(struct dvb_frontend *fe) d->tuner_pass_ctrl(fe,0,d->pll_addr); return ret; } -EXPORT_SYMBOL(dvb_usb_pll_init_i2c); +EXPORT_SYMBOL(dvb_usb_tuner_init_i2c); -int dvb_usb_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 b[5]) +int dvb_usb_tuner_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep, u8 *b, int buf_len) { struct dvb_usb_device *d = fe->dvb->priv; + if (buf_len != 5) + return -EINVAL; if (d->pll_desc == NULL) return 0; deb_pll("pll addr: %x, freq: %d %p\n",d->pll_addr,fep->frequency,d->pll_desc); - b[0] = d->pll_addr << 1; + b[0] = d->pll_addr; dvb_pll_configure(d->pll_desc,&b[1],fep->frequency,fep->u.ofdm.bandwidth); deb_pll("pll-buf: %x %x %x %x %x\n",b[0],b[1],b[2],b[3],b[4]); - return 0; + return 5; } -EXPORT_SYMBOL(dvb_usb_pll_set); +EXPORT_SYMBOL(dvb_usb_tuner_calc_regs); -int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) +int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters *fep) { struct dvb_usb_device *d = fe->dvb->priv; int ret = 0; u8 b[5]; struct i2c_msg msg = { .addr = d->pll_addr, .flags = 0, .buf = &b[1], .len = 4 }; - dvb_usb_pll_set(fe,fep,b); + dvb_usb_tuner_calc_regs(fe,fep,b,5); if (d->tuner_pass_ctrl) d->tuner_pass_ctrl(fe,1,d->pll_addr); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer (&d->i2c_adap, &msg, 1) != 1) { err("tuner i2c write failed for pll_set."); ret = -EREMOTEIO; @@ -116,4 +122,4 @@ int dvb_usb_pll_set_i2c(struct dvb_frontend *fe, struct dvb_frontend_parameters return ret; } -EXPORT_SYMBOL(dvb_usb_pll_set_i2c); +EXPORT_SYMBOL(dvb_usb_tuner_set_params_i2c); diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h index cb239049b09..95698918bc1 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h @@ -31,6 +31,7 @@ #define USB_VID_VISIONPLUS 0x13d3 #define USB_VID_TWINHAN 0x1822 #define USB_VID_ULTIMA_ELECTRONIC 0x05d8 +#define USB_VID_GENPIX 0x09c0 /* Product IDs */ #define USB_PID_ADSTECH_USB2_COLD 0xa333 @@ -104,5 +105,6 @@ #define USB_PID_KYE_DVB_T_WARM 0x701f #define USB_PID_PCTV_200E 0x020e #define USB_PID_PCTV_400E 0x020f - +#define USB_PID_GENPIX_8PSK_COLD 0x0200 +#define USB_PID_GENPIX_8PSK_WARM 0x0201 #endif diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h index fead958a57e..4cf9f89c51b 100644 --- a/drivers/media/dvb/dvb-usb/dvb-usb.h +++ b/drivers/media/dvb/dvb-usb/dvb-usb.h @@ -330,9 +330,9 @@ extern int dvb_usb_generic_write(struct dvb_usb_device *, u8 *, u16); extern int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *, u8[], u32 *, int *); /* commonly used pll init and set functions */ -extern int dvb_usb_pll_init_i2c(struct dvb_frontend *); -extern int dvb_usb_pll_set(struct dvb_frontend *, struct dvb_frontend_parameters *, u8[]); -extern int dvb_usb_pll_set_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *); +extern int dvb_usb_tuner_init_i2c(struct dvb_frontend *); +extern int dvb_usb_tuner_calc_regs(struct dvb_frontend *, struct dvb_frontend_parameters *, u8 *buf, int buf_len); +extern int dvb_usb_tuner_set_params_i2c(struct dvb_frontend *, struct dvb_frontend_parameters *); /* commonly used firmware download types and function */ struct hexline { diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c new file mode 100644 index 00000000000..6ccbdc9cd77 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c @@ -0,0 +1,272 @@ +/* DVB USB compliant Linux driver for the + * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * + * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * + * Thanks to GENPIX for the sample code used to implement this module. + * + * This module is based off the vp7045 and vp702x modules + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "gp8psk.h" + +struct gp8psk_fe_state { + struct dvb_frontend fe; + + struct dvb_usb_device *d; + + u16 snr; + + unsigned long next_snr_check; +}; + +static int gp8psk_fe_read_status(struct dvb_frontend* fe, fe_status_t *status) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + u8 lock; + + if (gp8psk_usb_in_op(st->d, GET_SIGNAL_LOCK, 0, 0, &lock,1)) + return -EINVAL; + + if (lock) + *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_SIGNAL | FE_HAS_CARRIER; + else + *status = 0; + + return 0; +} + +/* not supported by this Frontend */ +static int gp8psk_fe_read_ber(struct dvb_frontend* fe, u32 *ber) +{ + (void) fe; + *ber = 0; + return 0; +} + +/* not supported by this Frontend */ +static int gp8psk_fe_read_unc_blocks(struct dvb_frontend* fe, u32 *unc) +{ + (void) fe; + *unc = 0; + return 0; +} + +static int gp8psk_fe_read_snr(struct dvb_frontend* fe, u16 *snr) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + u8 buf[2]; + + if (time_after(jiffies,st->next_snr_check)) { + gp8psk_usb_in_op(st->d,GET_SIGNAL_STRENGTH,0,0,buf,2); + *snr = (int)(buf[1]) << 8 | buf[0]; + /* snr is reported in dBu*256 */ + /* snr / 38.4 ~= 100% strength */ + /* snr * 17 returns 100% strength as 65535 */ + if (*snr <= 3855) + *snr = (*snr<<4) + *snr; // snr * 17 + else + *snr = 65535; + st->next_snr_check = jiffies + (10*HZ)/1000; + } else { + *snr = st->snr; + } + return 0; +} + +static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength) +{ + return gp8psk_fe_read_snr(fe, strength); +} + +static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune) +{ + tune->min_delay_ms = 800; + return 0; +} + +static int gp8psk_fe_set_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + struct gp8psk_fe_state *state = fe->demodulator_priv; + u8 cmd[10]; + u32 freq = fep->frequency * 1000; + + cmd[4] = freq & 0xff; + cmd[5] = (freq >> 8) & 0xff; + cmd[6] = (freq >> 16) & 0xff; + cmd[7] = (freq >> 24) & 0xff; + + switch(fe->ops.info.type) { + case FE_QPSK: + cmd[0] = fep->u.qpsk.symbol_rate & 0xff; + cmd[1] = (fep->u.qpsk.symbol_rate >> 8) & 0xff; + cmd[2] = (fep->u.qpsk.symbol_rate >> 16) & 0xff; + cmd[3] = (fep->u.qpsk.symbol_rate >> 24) & 0xff; + cmd[8] = ADV_MOD_DVB_QPSK; + cmd[9] = 0x03; /*ADV_MOD_FEC_XXX*/ + break; + default: + // other modes are unsuported right now + cmd[0] = 0; + cmd[1] = 0; + cmd[2] = 0; + cmd[3] = 0; + cmd[8] = 0; + cmd[9] = 0; + break; + } + + gp8psk_usb_out_op(state->d,TUNE_8PSK,0,0,cmd,10); + + state->next_snr_check = jiffies; + + return 0; +} + +static int gp8psk_fe_get_frontend(struct dvb_frontend* fe, + struct dvb_frontend_parameters *fep) +{ + return 0; +} + + +static int gp8psk_fe_send_diseqc_msg (struct dvb_frontend* fe, + struct dvb_diseqc_master_cmd *m) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + + deb_fe("%s\n",__FUNCTION__); + + if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, m->msg[0], 0, + m->msg, m->msg_len)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_send_diseqc_burst (struct dvb_frontend* fe, + fe_sec_mini_cmd_t burst) +{ + struct gp8psk_fe_state *st = fe->demodulator_priv; + u8 cmd; + + deb_fe("%s\n",__FUNCTION__); + + /* These commands are certainly wrong */ + cmd = (burst == SEC_MINI_A) ? 0x00 : 0x01; + + if (gp8psk_usb_out_op(st->d,SEND_DISEQC_COMMAND, cmd, 0, + &cmd, 0)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + + if (gp8psk_usb_out_op(state->d,SET_22KHZ_TONE, + (tone == SEC_TONE_ON), 0, NULL, 0)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + + if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, + voltage == SEC_VOLTAGE_18, 0, NULL, 0)) { + return -EINVAL; + } + return 0; +} + +static int gp8psk_fe_send_legacy_dish_cmd (struct dvb_frontend* fe, unsigned long sw_cmd) +{ + struct gp8psk_fe_state* state = fe->demodulator_priv; + u8 cmd = sw_cmd & 0x7f; + + if (gp8psk_usb_out_op(state->d,SET_DN_SWITCH, cmd, 0, + NULL, 0)) { + return -EINVAL; + } + if (gp8psk_usb_out_op(state->d,SET_LNB_VOLTAGE, !!(sw_cmd & 0x80), + 0, NULL, 0)) { + return -EINVAL; + } + + return 0; +} + +static void gp8psk_fe_release(struct dvb_frontend* fe) +{ + struct gp8psk_fe_state *state = fe->demodulator_priv; + kfree(state); +} + +static struct dvb_frontend_ops gp8psk_fe_ops; + +struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d) +{ + struct gp8psk_fe_state *s = kzalloc(sizeof(struct gp8psk_fe_state), GFP_KERNEL); + if (s == NULL) + goto error; + + s->d = d; + memcpy(&s->fe.ops, &gp8psk_fe_ops, sizeof(struct dvb_frontend_ops)); + s->fe.demodulator_priv = s; + + goto success; +error: + return NULL; +success: + return &s->fe; +} + + +static struct dvb_frontend_ops gp8psk_fe_ops = { + .info = { + .name = "Genpix 8psk-USB DVB-S", + .type = FE_QPSK, + .frequency_min = 950000, + .frequency_max = 2150000, + .frequency_stepsize = 100, + .symbol_rate_min = 1000000, + .symbol_rate_max = 45000000, + .symbol_rate_tolerance = 500, /* ppm */ + .caps = FE_CAN_INVERSION_AUTO | + 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_QPSK + }, + + .release = gp8psk_fe_release, + + .init = NULL, + .sleep = NULL, + + .set_frontend = gp8psk_fe_set_frontend, + .get_frontend = gp8psk_fe_get_frontend, + .get_tune_settings = gp8psk_fe_get_tune_settings, + + .read_status = gp8psk_fe_read_status, + .read_ber = gp8psk_fe_read_ber, + .read_signal_strength = gp8psk_fe_read_signal_strength, + .read_snr = gp8psk_fe_read_snr, + .read_ucblocks = gp8psk_fe_read_unc_blocks, + + .diseqc_send_master_cmd = gp8psk_fe_send_diseqc_msg, + .diseqc_send_burst = gp8psk_fe_send_diseqc_burst, + .set_tone = gp8psk_fe_set_tone, + .set_voltage = gp8psk_fe_set_voltage, + .dishnetwork_send_legacy_command = gp8psk_fe_send_legacy_dish_cmd, +}; diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c new file mode 100644 index 00000000000..9a98f3fdae3 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/gp8psk.c @@ -0,0 +1,256 @@ +/* DVB USB compliant Linux driver for the + * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * + * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * + * Thanks to GENPIX for the sample code used to implement this module. + * + * This module is based off the vp7045 and vp702x modules + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#include "gp8psk.h" + +/* debug */ +static char bcm4500_firmware[] = "dvb-usb-gp8psk-02.fw"; +int dvb_usb_gp8psk_debug; +module_param_named(debug,dvb_usb_gp8psk_debug, int, 0644); +MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DVB_USB_DEBUG_STATUS); + +int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen) +{ + int ret = 0,try = 0; + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + while (ret >= 0 && ret != blen && try < 3) { + ret = usb_control_msg(d->udev, + usb_rcvctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_IN, + value,index,b,blen, + 2000); + deb_info("reading number %d (ret: %d)\n",try,ret); + try++; + } + + if (ret < 0 || ret != blen) { + warn("usb in operation failed."); + ret = -EIO; + } else + ret = 0; + + deb_xfer("in: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + mutex_unlock(&d->usb_mutex); + + return ret; +} + +int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen) +{ + int ret; + + deb_xfer("out: req. %x, val: %x, ind: %x, buffer: ",req,value,index); + debug_dump(b,blen,deb_xfer); + + if ((ret = mutex_lock_interruptible(&d->usb_mutex))) + return ret; + + if (usb_control_msg(d->udev, + usb_sndctrlpipe(d->udev,0), + req, + USB_TYPE_VENDOR | USB_DIR_OUT, + value,index,b,blen, + 2000) != blen) { + warn("usb out operation failed."); + ret = -EIO; + } else + ret = 0; + mutex_unlock(&d->usb_mutex); + + return ret; +} + +static int gp8psk_load_bcm4500fw(struct dvb_usb_device *d) +{ + int ret; + const struct firmware *fw = NULL; + u8 *ptr, *buf; + if ((ret = request_firmware(&fw, bcm4500_firmware, + &d->udev->dev)) != 0) { + err("did not find the bcm4500 firmware file. (%s) " + "Please see linux/Documentation/dvb/ for more details on firmware-problems. (%d)", + bcm4500_firmware,ret); + return ret; + } + + ret = -EINVAL; + + if (gp8psk_usb_out_op(d, LOAD_BCM4500,1,0,NULL, 0)) + goto out_rel_fw; + + info("downloaidng bcm4500 firmware from file '%s'",bcm4500_firmware); + + ptr = fw->data; + buf = kmalloc(512, GFP_KERNEL | GFP_DMA); + + while (ptr[0] != 0xff) { + u16 buflen = ptr[0] + 4; + if (ptr + buflen >= fw->data + fw->size) { + err("failed to load bcm4500 firmware."); + goto out_free; + } + memcpy(buf, ptr, buflen); + if (dvb_usb_generic_write(d, buf, buflen)) { + err("failed to load bcm4500 firmware."); + goto out_free; + } + ptr += buflen; + } + + ret = 0; + +out_free: + kfree(buf); +out_rel_fw: + release_firmware(fw); + + return ret; +} + +static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff) +{ + u8 status, buf; + if (onoff) { + gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); + if (! (status & 0x01)) /* started */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1)) + return -EINVAL; + + if (! (status & 0x02)) /* BCM4500 firmware loaded */ + if(gp8psk_load_bcm4500fw(d)) + return EINVAL; + + if (! (status & 0x04)) /* LNB Power */ + if (gp8psk_usb_in_op(d, START_INTERSIL, 1, 0, + &buf, 1)) + return EINVAL; + + /* Set DVB mode */ + if(gp8psk_usb_out_op(d, SET_DVB_MODE, 1, 0, NULL, 0)) + return -EINVAL; + gp8psk_usb_in_op(d, GET_8PSK_CONFIG,0,0,&status,1); + } else { + /* Turn off LNB power */ + if (gp8psk_usb_in_op(d, START_INTERSIL, 0, 0, &buf, 1)) + return EINVAL; + /* Turn off 8psk power */ + if (gp8psk_usb_in_op(d, BOOT_8PSK, 0, 0, &buf, 1)) + return -EINVAL; + + } + return 0; +} + + +static int gp8psk_streaming_ctrl(struct dvb_usb_device *d, int onoff) +{ + return gp8psk_usb_out_op(d, ARM_TRANSFER, onoff, 0 , NULL, 0); +} + +static int gp8psk_frontend_attach(struct dvb_usb_device *d) +{ + d->fe = gp8psk_fe_attach(d); + + return 0; +} + +static struct dvb_usb_properties gp8psk_properties; + +static int gp8psk_usb_probe(struct usb_interface *intf, + const struct usb_device_id *id) +{ + return dvb_usb_device_init(intf,&gp8psk_properties,THIS_MODULE,NULL); +} + +static struct usb_device_id gp8psk_usb_table [] = { + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_COLD) }, + { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_WARM) }, + { 0 }, +}; +MODULE_DEVICE_TABLE(usb, gp8psk_usb_table); + +static struct dvb_usb_properties gp8psk_properties = { + .caps = 0, + + .usb_ctrl = CYPRESS_FX2, + .firmware = "dvb-usb-gp8psk-01.fw", + + .streaming_ctrl = gp8psk_streaming_ctrl, + .power_ctrl = gp8psk_power_ctrl, + .frontend_attach = gp8psk_frontend_attach, + + .generic_bulk_ctrl_endpoint = 0x01, + /* parameter for the MPEG2-data transfer */ + .urb = { + .type = DVB_USB_BULK, + .count = 7, + .endpoint = 0x82, + .u = { + .bulk = { + .buffersize = 8192, + } + } + }, + + .num_device_descs = 1, + .devices = { + { .name = "Genpix 8PSK-USB DVB-S USB2.0 receiver", + .cold_ids = { &gp8psk_usb_table[0], NULL }, + .warm_ids = { &gp8psk_usb_table[1], NULL }, + }, + { 0 }, + } +}; + +/* usb specific object needed to register this driver with the usb subsystem */ +static struct usb_driver gp8psk_usb_driver = { + .name = "dvb_usb_gp8psk", + .probe = gp8psk_usb_probe, + .disconnect = dvb_usb_device_exit, + .id_table = gp8psk_usb_table, +}; + +/* module stuff */ +static int __init gp8psk_usb_module_init(void) +{ + int result; + if ((result = usb_register(&gp8psk_usb_driver))) { + err("usb_register failed. (%d)",result); + return result; + } + + return 0; +} + +static void __exit gp8psk_usb_module_exit(void) +{ + /* deregister this driver from the USB subsystem */ + usb_deregister(&gp8psk_usb_driver); +} + +module_init(gp8psk_usb_module_init); +module_exit(gp8psk_usb_module_exit); + +MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>"); +MODULE_DESCRIPTION("Driver for Genpix 8psk-USB DVB-S USB2.0"); +MODULE_VERSION("1.0"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h new file mode 100644 index 00000000000..3eba7061011 --- /dev/null +++ b/drivers/media/dvb/dvb-usb/gp8psk.h @@ -0,0 +1,79 @@ +/* DVB USB compliant Linux driver for the + * - GENPIX 8pks/qpsk USB2.0 DVB-S module + * + * Copyright (C) 2006 Alan Nisota (alannisota@gmail.com) + * + * Thanks to GENPIX for the sample code used to implement this module. + * + * This module is based off the vp7045 and vp702x modules + * + * 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, version 2. + * + * see Documentation/dvb/README.dvb-usb for more information + */ +#ifndef _DVB_USB_GP8PSK_H_ +#define _DVB_USB_GP8PSK_H_ + +#define DVB_USB_LOG_PREFIX "gp8psk" +#include "dvb-usb.h" + +extern int dvb_usb_gp8psk_debug; +#define deb_info(args...) dprintk(dvb_usb_gp8psk_debug,0x01,args) +#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args) +#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args) +#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args) +/* gp8psk commands */ + +/* Twinhan Vendor requests */ +#define TH_COMMAND_IN 0xC0 +#define TH_COMMAND_OUT 0xC1 + +/* command bytes */ +#define GET_8PSK_CONFIG 0x80 +#define SET_8PSK_CONFIG 0x81 +#define ARM_TRANSFER 0x85 +#define TUNE_8PSK 0x86 +#define GET_SIGNAL_STRENGTH 0x87 +#define LOAD_BCM4500 0x88 +#define BOOT_8PSK 0x89 +#define START_INTERSIL 0x8A +#define SET_LNB_VOLTAGE 0x8B +#define SET_22KHZ_TONE 0x8C +#define SEND_DISEQC_COMMAND 0x8D +#define SET_DVB_MODE 0x8E +#define SET_DN_SWITCH 0x8F +#define GET_SIGNAL_LOCK 0x90 + +/* Satellite modulation modes */ +#define ADV_MOD_DVB_QPSK 0 /* DVB-S QPSK */ +#define ADV_MOD_TURBO_QPSK 1 /* Turbo QPSK */ +#define ADV_MOD_TURBO_8PSK 2 /* Turbo 8PSK (also used for Trellis 8PSK) */ +#define ADV_MOD_TURBO_16QAM 3 /* Turbo 16QAM (also used for Trellis 8PSK) */ + +#define ADV_MOD_DCII_C_QPSK 4 /* Digicipher II Combo */ +#define ADV_MOD_DCII_I_QPSK 5 /* Digicipher II I-stream */ +#define ADV_MOD_DCII_Q_QPSK 6 /* Digicipher II Q-stream */ +#define ADV_MOD_DCII_C_OQPSK 7 /* Digicipher II offset QPSK */ +#define ADV_MOD_DSS_QPSK 8 /* DSS (DIRECTV) QPSK */ +#define ADV_MOD_DVB_BPSK 9 /* DVB-S BPSK */ + +#define GET_USB_SPEED 0x07 + #define USB_SPEED_LOW 0 + #define USB_SPEED_FULL 1 + #define USB_SPEED_HIGH 2 + +#define RESET_FX2 0x13 + +#define FW_VERSION_READ 0x0B +#define VENDOR_STRING_READ 0x0C +#define PRODUCT_STRING_READ 0x0D +#define FW_BCD_VERSION_READ 0x14 + +extern struct dvb_frontend * gp8psk_fe_attach(struct dvb_usb_device *d); +extern int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen); +extern int gp8psk_usb_out_op(struct dvb_usb_device *d, u8 req, u16 value, + u16 index, u8 *b, int blen); + +#endif diff --git a/drivers/media/dvb/dvb-usb/umt-010.c b/drivers/media/dvb/dvb-usb/umt-010.c index 14f1911c79b..97d74da0dad 100644 --- a/drivers/media/dvb/dvb-usb/umt-010.c +++ b/drivers/media/dvb/dvb-usb/umt-010.c @@ -57,7 +57,6 @@ static int umt_mt352_frontend_attach(struct dvb_usb_device *d) memset(&umt_config,0,sizeof(struct mt352_config)); umt_config.demod_init = umt_mt352_demod_init; umt_config.demod_address = 0xf; - umt_config.pll_set = dvb_usb_pll_set; d->fe = mt352_attach(&umt_config, &d->i2c_adap); @@ -68,6 +67,7 @@ static int umt_tuner_attach (struct dvb_usb_device *d) { d->pll_addr = 0x61; d->pll_desc = &dvb_pll_tua6034; + d->fe->ops.tuner_ops.calc_regs = dvb_usb_tuner_calc_regs; return 0; } diff --git a/drivers/media/dvb/dvb-usb/vp702x-fe.c b/drivers/media/dvb/dvb-usb/vp702x-fe.c index 2a89f8c5da9..d4da494132e 100644 --- a/drivers/media/dvb/dvb-usb/vp702x-fe.c +++ b/drivers/media/dvb/dvb-usb/vp702x-fe.c @@ -287,17 +287,16 @@ struct dvb_frontend * vp702x_fe_attach(struct dvb_usb_device *d) goto error; s->d = d; - s->fe.ops = &vp702x_fe_ops; + + memcpy(&s->fe.ops,&vp702x_fe_ops,sizeof(struct dvb_frontend_ops)); s->fe.demodulator_priv = s; s->lnb_buf[1] = SET_LNB_POWER; s->lnb_buf[3] = 0xff; /* 0=tone burst, 2=data burst, ff=off */ - goto success; + return &s->fe; error: return NULL; -success: - return &s->fe; } diff --git a/drivers/media/dvb/dvb-usb/vp7045-fe.c b/drivers/media/dvb/dvb-usb/vp7045-fe.c index 9999336aeeb..8452eef9032 100644 --- a/drivers/media/dvb/dvb-usb/vp7045-fe.c +++ b/drivers/media/dvb/dvb-usb/vp7045-fe.c @@ -23,8 +23,6 @@ struct vp7045_fe_state { struct dvb_frontend fe; - struct dvb_frontend_ops ops; - struct dvb_usb_device *d; }; @@ -151,15 +149,12 @@ struct dvb_frontend * vp7045_fe_attach(struct dvb_usb_device *d) goto error; s->d = d; - memcpy(&s->ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops)); - s->fe.ops = &s->ops; + memcpy(&s->fe.ops, &vp7045_fe_ops, sizeof(struct dvb_frontend_ops)); s->fe.demodulator_priv = s; - goto success; + return &s->fe; error: return NULL; -success: - return &s->fe; } diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig index 37d5e0af168..0ef361f0309 100644 --- a/drivers/media/dvb/frontends/Kconfig +++ b/drivers/media/dvb/frontends/Kconfig @@ -157,7 +157,7 @@ config DVB_STV0297 help A DVB-C tuner module. Say Y when you want to support this frontend. -comment "ATSC (North American/Korean Terresterial DTV) frontends" +comment "ATSC (North American/Korean Terrestrial/Cable DTV) frontends" depends on DVB_CORE config DVB_NXT200X @@ -216,4 +216,20 @@ config DVB_LGDT330X An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want to support this frontend. + +comment "Miscellaneous devices" + depends on DVB_CORE + +config DVB_LNBP21 + tristate "LNBP21 SEC controller" + depends on DVB_CORE + help + An SEC control chip. + +config DVB_ISL6421 + tristate "ISL6421 SEC controller" + depends on DVB_CORE + help + An SEC control chip. + endmenu diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile index d09b6071fba..5222245c7f5 100644 --- a/drivers/media/dvb/frontends/Makefile +++ b/drivers/media/dvb/frontends/Makefile @@ -31,3 +31,5 @@ obj-$(CONFIG_DVB_BCM3510) += bcm3510.o obj-$(CONFIG_DVB_S5H1420) += s5h1420.o obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o obj-$(CONFIG_DVB_CX24123) += cx24123.o +obj-$(CONFIG_DVB_LNBP21) += lnbp21.o +obj-$(CONFIG_DVB_ISL6421) += isl6421.o diff --git a/drivers/media/dvb/frontends/bcm3510.c b/drivers/media/dvb/frontends/bcm3510.c index 1708a1d4893..baeb311de89 100644 --- a/drivers/media/dvb/frontends/bcm3510.c +++ b/drivers/media/dvb/frontends/bcm3510.c @@ -48,7 +48,6 @@ struct bcm3510_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; const struct bcm3510_config* config; struct dvb_frontend frontend; @@ -791,10 +790,9 @@ struct dvb_frontend* bcm3510_attach(const struct bcm3510_config *config, state->config = config; state->i2c = i2c; - memcpy(&state->ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops)); /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &bcm3510_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; mutex_init(&state->hab_mutex); diff --git a/drivers/media/dvb/frontends/bsbe1.h b/drivers/media/dvb/frontends/bsbe1.h index 78573b22ada..d8f65738e5d 100644 --- a/drivers/media/dvb/frontends/bsbe1.h +++ b/drivers/media/dvb/frontends/bsbe1.h @@ -89,12 +89,13 @@ static int alps_bsbe1_set_symbol_rate(struct dvb_frontend* fe, u32 srate, u32 ra return 0; } -static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters* params) +static int alps_bsbe1_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) { int ret; u8 data[4]; u32 div; struct i2c_msg msg = { .addr = 0x61, .flags = 0, .buf = data, .len = sizeof(data) }; + struct i2c_adapter *i2c = fe->tuner_priv; if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL; @@ -105,6 +106,8 @@ static int alps_bsbe1_pll_set(struct dvb_frontend* fe, struct i2c_adapter *i2c, data[2] = 0x80 | ((div & 0x18000) >> 10) | 4; data[3] = (params->frequency > 1530000) ? 0xE0 : 0xE4; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); ret = i2c_transfer(i2c, &msg, 1); return (ret != 1) ? -EIO : 0; } @@ -117,7 +120,6 @@ static struct stv0299_config alps_bsbe1_config = { .skip_reinit = 0, .min_delay_ms = 100, .set_symbol_rate = alps_bsbe1_set_symbol_rate, - .pll_set = alps_bsbe1_pll_set, }; #endif diff --git a/drivers/media/dvb/frontends/bsru6.h b/drivers/media/dvb/frontends/bsru6.h index 2a5366ce79c..e231cd84b3a 100644 --- a/drivers/media/dvb/frontends/bsru6.h +++ b/drivers/media/dvb/frontends/bsru6.h @@ -101,11 +101,12 @@ static int alps_bsru6_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 ra return 0; } -static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params) +static int alps_bsru6_tuner_set_params(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 i2c_adapter *i2c = fe->tuner_priv; if ((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL; @@ -119,6 +120,8 @@ static int alps_bsru6_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, if (params->frequency > 1530000) buf[3] = 0xc0; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(i2c, &msg, 1) != 1) return -EIO; return 0; @@ -134,7 +137,6 @@ static struct stv0299_config alps_bsru6_config = { .volt13_op0_op1 = STV0299_VOLT13_OP1, .min_delay_ms = 100, .set_symbol_rate = alps_bsru6_set_symbol_rate, - .pll_set = alps_bsru6_pll_set, }; #endif diff --git a/drivers/media/dvb/frontends/cx22700.c b/drivers/media/dvb/frontends/cx22700.c index 755f774f6b7..3c7c09a362b 100644 --- a/drivers/media/dvb/frontends/cx22700.c +++ b/drivers/media/dvb/frontends/cx22700.c @@ -34,8 +34,6 @@ struct cx22700_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; - const struct cx22700_config* config; struct dvb_frontend frontend; @@ -247,12 +245,6 @@ static int cx22700_init (struct dvb_frontend* fe) cx22700_writereg (state, 0x00, 0x01); - if (state->config->pll_init) { - cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */ - state->config->pll_init(fe); - cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */ - } - return 0; } @@ -333,9 +325,11 @@ static int cx22700_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par cx22700_writereg (state, 0x00, 0x02); /* XXX CHECKME: soft reset*/ cx22700_writereg (state, 0x00, 0x00); - cx22700_writereg (state, 0x0a, 0x00); /* open i2c bus switch */ - state->config->pll_set(fe, p); - cx22700_writereg (state, 0x0a, 0x01); /* close i2c bus switch */ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + cx22700_set_inversion (state, p->inversion); cx22700_set_tps (state, &p->u.ofdm); cx22700_writereg (state, 0x37, 0x01); /* PAL loop filter off */ @@ -353,6 +347,17 @@ static int cx22700_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par return cx22700_get_tps (state, &p->u.ofdm); } +static int cx22700_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct cx22700_state* state = fe->demodulator_priv; + + if (enable) { + return cx22700_writereg(state, 0x0a, 0x00); + } else { + return cx22700_writereg(state, 0x0a, 0x01); + } +} + static int cx22700_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { fesettings->min_delay_ms = 150; @@ -381,13 +386,12 @@ struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &cx22700_ops, sizeof(struct dvb_frontend_ops)); /* check if the demod is there */ if (cx22700_readreg(state, 0x07) < 0) goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &cx22700_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -413,6 +417,7 @@ static struct dvb_frontend_ops cx22700_ops = { .release = cx22700_release, .init = cx22700_init, + .i2c_gate_ctrl = cx22700_i2c_gate_ctrl, .set_frontend = cx22700_set_frontend, .get_frontend = cx22700_get_frontend, diff --git a/drivers/media/dvb/frontends/cx22700.h b/drivers/media/dvb/frontends/cx22700.h index c9145b45874..dcd8979c1a1 100644 --- a/drivers/media/dvb/frontends/cx22700.h +++ b/drivers/media/dvb/frontends/cx22700.h @@ -29,10 +29,6 @@ struct cx22700_config { /* the demodulator's i2c address */ u8 demod_address; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; extern struct dvb_frontend* cx22700_attach(const struct cx22700_config* config, diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c index 0fc899f81c5..4106d46c957 100644 --- a/drivers/media/dvb/frontends/cx22702.c +++ b/drivers/media/dvb/frontends/cx22702.c @@ -40,8 +40,6 @@ struct cx22702_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; - /* configuration settings */ const struct cx22702_config* config; @@ -211,22 +209,10 @@ static int cx22702_set_tps (struct dvb_frontend* fe, struct dvb_frontend_paramet u8 val; struct cx22702_state* state = fe->demodulator_priv; - /* set PLL */ - cx22702_i2c_gate_ctrl(fe, 1); - if (state->config->pll_set) { - state->config->pll_set(fe, p); - } else if (state->config->pll_desc) { - u8 pllbuf[4]; - struct i2c_msg msg = { .addr = state->config->pll_address, - .buf = pllbuf, .len = 4 }; - dvb_pll_configure(state->config->pll_desc, pllbuf, - p->frequency, - p->u.ofdm.bandwidth); - i2c_transfer(state->i2c, &msg, 1); - } else { - BUG(); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - cx22702_i2c_gate_ctrl(fe, 0); /* set inversion */ cx22702_set_inversion (state, p->inversion); @@ -358,10 +344,6 @@ static int cx22702_init (struct dvb_frontend* fe) cx22702_writereg (state, 0xf8, (state->config->output_mode << 1) & 0x02); - /* init PLL */ - if (state->config->pll_init) - state->config->pll_init(fe); - cx22702_i2c_gate_ctrl(fe, 0); return 0; @@ -495,7 +477,6 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &cx22702_ops, sizeof(struct dvb_frontend_ops)); state->prevUCBlocks = 0; /* check if the demod is there */ @@ -503,7 +484,7 @@ struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &cx22702_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -530,6 +511,7 @@ static struct dvb_frontend_ops cx22702_ops = { .release = cx22702_release, .init = cx22702_init, + .i2c_gate_ctrl = cx22702_i2c_gate_ctrl, .set_frontend = cx22702_set_tps, .get_frontend = cx22702_get_frontend, @@ -540,7 +522,6 @@ static struct dvb_frontend_ops cx22702_ops = { .read_signal_strength = cx22702_read_signal_strength, .read_snr = cx22702_read_snr, .read_ucblocks = cx22702_read_ucblocks, - .i2c_gate_ctrl = cx22702_i2c_gate_ctrl, }; module_param(debug, int, 0644); diff --git a/drivers/media/dvb/frontends/cx22702.h b/drivers/media/dvb/frontends/cx22702.h index 5633976a58f..7f2f241e5d4 100644 --- a/drivers/media/dvb/frontends/cx22702.h +++ b/drivers/media/dvb/frontends/cx22702.h @@ -39,13 +39,6 @@ struct cx22702_config #define CX22702_PARALLEL_OUTPUT 0 #define CX22702_SERIAL_OUTPUT 1 u8 output_mode; - - /* PLL maintenance */ - u8 pll_address; - struct dvb_pll_desc *pll_desc; - - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; extern struct dvb_frontend* cx22702_attach(const struct cx22702_config* config, diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c index f3edf8b517d..ce3c7398bac 100644 --- a/drivers/media/dvb/frontends/cx24110.c +++ b/drivers/media/dvb/frontends/cx24110.c @@ -36,8 +36,6 @@ struct cx24110_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; - const struct cx24110_config* config; struct dvb_frontend frontend; @@ -250,7 +248,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate) static const u32 bands[]={5000000UL,15000000UL,90999000UL/2}; int i; -dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate); + dprintk("cx24110 debug: entering %s(%d)\n",__FUNCTION__,srate); if (srate>90999000UL/2) srate=90999000UL/2; if (srate<500000) @@ -366,17 +364,6 @@ static int cx24110_initfe(struct dvb_frontend* fe) cx24110_writereg(state, cx24110_regdata[i].reg, cx24110_regdata[i].data); }; - if (state->config->pll_init) state->config->pll_init(fe); - - return 0; -} - -static int cx24110_sleep(struct dvb_frontend *fe) -{ - struct cx24110_state *state = fe->demodulator_priv; - - if (state->config->pll_sleep) - return state->config->pll_sleep(fe); return 0; } @@ -548,7 +535,12 @@ static int cx24110_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par { struct cx24110_state *state = fe->demodulator_priv; - state->config->pll_set(fe, p); + + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + cx24110_set_inversion (state, p->inversion); cx24110_set_fec (state, p->u.qpsk.fec_inner); cx24110_set_symbolrate (state, p->u.qpsk.symbol_rate); @@ -612,7 +604,6 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &cx24110_ops, sizeof(struct dvb_frontend_ops)); state->lastber = 0; state->lastbler = 0; state->lastesn0 = 0; @@ -622,7 +613,7 @@ struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, if ((ret != 0x5a) && (ret != 0x69)) goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &cx24110_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -651,7 +642,6 @@ static struct dvb_frontend_ops cx24110_ops = { .release = cx24110_release, .init = cx24110_initfe, - .sleep = cx24110_sleep, .set_frontend = cx24110_set_frontend, .get_frontend = cx24110_get_frontend, .read_status = cx24110_read_status, diff --git a/drivers/media/dvb/frontends/cx24110.h b/drivers/media/dvb/frontends/cx24110.h index 609ac642b40..b354a64e0e7 100644 --- a/drivers/media/dvb/frontends/cx24110.h +++ b/drivers/media/dvb/frontends/cx24110.h @@ -31,11 +31,6 @@ struct cx24110_config { /* the demodulator's i2c address */ u8 demod_address; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - int (*pll_sleep)(struct dvb_frontend* fe); }; extern struct dvb_frontend* cx24110_attach(const struct cx24110_config* config, diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c index 691dc840dcc..f2f795cba56 100644 --- a/drivers/media/dvb/frontends/cx24123.c +++ b/drivers/media/dvb/frontends/cx24123.c @@ -41,14 +41,12 @@ static int debug; struct cx24123_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; const struct cx24123_config* config; struct dvb_frontend frontend; u32 lastber; u16 snr; - u8 lnbreg; /* Some PLL specifics for tuning */ u32 VCAarg; @@ -249,29 +247,6 @@ static int cx24123_writereg(struct cx24123_state* state, int reg, int data) return 0; } -static int cx24123_writelnbreg(struct cx24123_state* state, int reg, int data) -{ - u8 buf[] = { reg, data }; - /* fixme: put the intersil addr int the config */ - struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = buf, .len = 2 }; - int err; - - if (debug>1) - printk("cx24123: %s: writeln addr=0x08, reg 0x%02x, value 0x%02x\n", - __FUNCTION__,reg, data); - - if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) { - printk("%s: writelnbreg error (err == %i, reg == 0x%02x," - " data == 0x%02x)\n", __FUNCTION__, err, reg, data); - return -EREMOTEIO; - } - - /* cache the write, no way to read back */ - state->lnbreg = data; - - return 0; -} - static int cx24123_readreg(struct cx24123_state* state, u8 reg) { int ret; @@ -295,11 +270,6 @@ static int cx24123_readreg(struct cx24123_state* state, u8 reg) return b1[0]; } -static int cx24123_readlnbreg(struct cx24123_state* state, u8 reg) -{ - return state->lnbreg; -} - static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion) { u8 nom_reg = cx24123_readreg(state, 0x0e); @@ -458,8 +428,8 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate) u8 pll_mult; /* check if symbol rate is within limits */ - if ((srate > state->ops.info.symbol_rate_max) || - (srate < state->ops.info.symbol_rate_min)) + if ((srate > state->frontend.ops.info.symbol_rate_max) || + (srate < state->frontend.ops.info.symbol_rate_min)) return -EOPNOTSUPP;; /* choose the sampling rate high enough for the required operation, @@ -687,13 +657,6 @@ static int cx24123_initfe(struct dvb_frontend* fe) for (i = 0; i < sizeof(cx24123_regdata) / sizeof(cx24123_regdata[0]); i++) cx24123_writereg(state, cx24123_regdata[i].reg, cx24123_regdata[i].data); - if (state->config->pll_init) - state->config->pll_init(fe); - - /* Configure the LNB for 14V */ - if (state->config->use_isl6421) - cx24123_writelnbreg(state, 0x0, 0x2a); - return 0; } @@ -702,50 +665,18 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage struct cx24123_state *state = fe->demodulator_priv; u8 val; - switch (state->config->use_isl6421) { - - case 1: + val = cx24123_readreg(state, 0x29) & ~0x40; - val = cx24123_readlnbreg(state, 0x0); - - switch (voltage) { - case SEC_VOLTAGE_13: - dprintk("%s: isl6421 voltage = 13V\n",__FUNCTION__); - return cx24123_writelnbreg(state, 0x0, val & 0x32); /* V 13v */ - case SEC_VOLTAGE_18: - dprintk("%s: isl6421 voltage = 18V\n",__FUNCTION__); - return cx24123_writelnbreg(state, 0x0, val | 0x04); /* H 18v */ - case SEC_VOLTAGE_OFF: - dprintk("%s: isl5421 voltage off\n",__FUNCTION__); - return cx24123_writelnbreg(state, 0x0, val & 0x30); - default: - return -EINVAL; - }; - - case 0: - - val = cx24123_readreg(state, 0x29); - - switch (voltage) { - case SEC_VOLTAGE_13: - dprintk("%s: setting voltage 13V\n", __FUNCTION__); - if (state->config->enable_lnb_voltage) - state->config->enable_lnb_voltage(fe, 1); - return cx24123_writereg(state, 0x29, val | 0x80); - case SEC_VOLTAGE_18: - dprintk("%s: setting voltage 18V\n", __FUNCTION__); - if (state->config->enable_lnb_voltage) - state->config->enable_lnb_voltage(fe, 1); - return cx24123_writereg(state, 0x29, val & 0x7f); - case SEC_VOLTAGE_OFF: - dprintk("%s: setting voltage off\n", __FUNCTION__); - if (state->config->enable_lnb_voltage) - state->config->enable_lnb_voltage(fe, 0); - return 0; - default: - return -EINVAL; - }; - } + switch (voltage) { + case SEC_VOLTAGE_13: + dprintk("%s: setting voltage 13V\n", __FUNCTION__); + return cx24123_writereg(state, 0x29, val | 0x80); + case SEC_VOLTAGE_18: + dprintk("%s: setting voltage 18V\n", __FUNCTION__); + return cx24123_writereg(state, 0x29, val & 0x7f); + default: + return -EINVAL; + }; return 0; } @@ -766,27 +697,20 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state) static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd *cmd) { struct cx24123_state *state = fe->demodulator_priv; - int i, val; + int i, val, tone; dprintk("%s:\n",__FUNCTION__); - /* check if continuous tone has been stopped */ - if (state->config->use_isl6421) - val = cx24123_readlnbreg(state, 0x00) & 0x10; - else - val = cx24123_readreg(state, 0x29) & 0x10; - - - if (val) { - printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__); - return -ENOTSUPP; - } + /* stop continuous tone if enabled */ + tone = cx24123_readreg(state, 0x29); + if (tone & 0x10) + cx24123_writereg(state, 0x29, tone & ~0x50); /* wait for diseqc queue ready */ cx24123_wait_for_diseqc(state); /* select tone mode */ - cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xf8); + cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb); for (i = 0; i < cmd->msg_len; i++) cx24123_writereg(state, 0x2C + i, cmd->msg[i]); @@ -797,36 +721,33 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma /* wait for diseqc message to finish sending */ cx24123_wait_for_diseqc(state); + /* restart continuous tone if enabled */ + if (tone & 0x10) { + cx24123_writereg(state, 0x29, tone & ~0x40); + } + return 0; } static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t burst) { struct cx24123_state *state = fe->demodulator_priv; - int val; + int val, tone; dprintk("%s:\n", __FUNCTION__); - /* check if continuous tone has been stoped */ - if (state->config->use_isl6421) - val = cx24123_readlnbreg(state, 0x00) & 0x10; - else - val = cx24123_readreg(state, 0x29) & 0x10; - - - if (val) { - printk("%s: ERROR: attempt to send diseqc command before tone is off\n", __FUNCTION__); - return -ENOTSUPP; - } + /* stop continuous tone if enabled */ + tone = cx24123_readreg(state, 0x29); + if (tone & 0x10) + cx24123_writereg(state, 0x29, tone & ~0x50); + /* wait for diseqc queue ready */ cx24123_wait_for_diseqc(state); /* select tone mode */ - val = cx24123_readreg(state, 0x2a) & 0xf8; - cx24123_writereg(state, 0x2a, val | 0x04); - + cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) | 0x4); + msleep(30); val = cx24123_readreg(state, 0x29); - if (burst == SEC_MINI_A) cx24123_writereg(state, 0x29, ((val & 0x90) | 0x40 | 0x00)); else if (burst == SEC_MINI_B) @@ -835,7 +756,12 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t return -EINVAL; cx24123_wait_for_diseqc(state); + cx24123_writereg(state, 0x2a, cx24123_readreg(state, 0x2a) & 0xfb); + /* restart continuous tone if enabled */ + if (tone & 0x10) { + cx24123_writereg(state, 0x29, tone & ~0x40); + } return 0; } @@ -976,38 +902,21 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone) struct cx24123_state *state = fe->demodulator_priv; u8 val; - switch (state->config->use_isl6421) { - case 1: - - val = cx24123_readlnbreg(state, 0x0); - - switch (tone) { - case SEC_TONE_ON: - dprintk("%s: isl6421 sec tone on\n",__FUNCTION__); - return cx24123_writelnbreg(state, 0x0, val | 0x10); - case SEC_TONE_OFF: - dprintk("%s: isl6421 sec tone off\n",__FUNCTION__); - return cx24123_writelnbreg(state, 0x0, val & 0x2f); - default: - printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); - return -EINVAL; - } - - case 0: + /* wait for diseqc queue ready */ + cx24123_wait_for_diseqc(state); - val = cx24123_readreg(state, 0x29); + val = cx24123_readreg(state, 0x29) & ~0x40; - switch (tone) { - case SEC_TONE_ON: - dprintk("%s: setting tone on\n", __FUNCTION__); - return cx24123_writereg(state, 0x29, val | 0x10); - case SEC_TONE_OFF: - dprintk("%s: setting tone off\n",__FUNCTION__); - return cx24123_writereg(state, 0x29, val & 0xef); - default: - printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); - return -EINVAL; - } + switch (tone) { + case SEC_TONE_ON: + dprintk("%s: setting tone on\n", __FUNCTION__); + return cx24123_writereg(state, 0x29, val | 0x10); + case SEC_TONE_OFF: + dprintk("%s: setting tone off\n",__FUNCTION__); + return cx24123_writereg(state, 0x29, val & 0xef); + default: + printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone); + return -EINVAL; } return 0; @@ -1040,10 +949,8 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &cx24123_ops, sizeof(struct dvb_frontend_ops)); state->lastber = 0; state->snr = 0; - state->lnbreg = 0; state->VCAarg = 0; state->VGAarg = 0; state->bandselectarg = 0; @@ -1059,7 +966,7 @@ struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, } /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h index 0c922b5e926..9606f825935 100644 --- a/drivers/media/dvb/frontends/cx24123.h +++ b/drivers/media/dvb/frontends/cx24123.h @@ -28,21 +28,8 @@ struct cx24123_config /* the demodulator's i2c address */ u8 demod_address; - /* - cards like Hauppauge Nova-S Plus/Nova-SE2 use an Intersil ISL6421 chip - for LNB control, while KWorld DVB-S 100 use the LNBDC and LNBTone bits - from register 0x29 of the CX24123 demodulator - */ - int use_isl6421; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - /* Need to set device param for start_dma */ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); - - void (*enable_lnb_voltage)(struct dvb_frontend* fe, int on); }; extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config, diff --git a/drivers/media/dvb/frontends/dib3000-common.h b/drivers/media/dvb/frontends/dib3000-common.h index c31d6df1547..be1c0d3e138 100644 --- a/drivers/media/dvb/frontends/dib3000-common.h +++ b/drivers/media/dvb/frontends/dib3000-common.h @@ -38,8 +38,6 @@ struct dib3000_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; - /* configuration settings */ struct dib3000_config config; diff --git a/drivers/media/dvb/frontends/dib3000.h b/drivers/media/dvb/frontends/dib3000.h index 2d5475b5c06..ec927628d27 100644 --- a/drivers/media/dvb/frontends/dib3000.h +++ b/drivers/media/dvb/frontends/dib3000.h @@ -30,10 +30,6 @@ struct dib3000_config { /* the demodulator's i2c address */ u8 demod_address; - - /* PLL maintenance and the i2c address of the PLL */ - int (*pll_init)(struct dvb_frontend *fe); - int (*pll_set)(struct dvb_frontend *fe, struct dvb_frontend_parameters* params); }; struct dib_fe_xfer_ops diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c index ae589adb1c0..7c6dc7e3090 100644 --- a/drivers/media/dvb/frontends/dib3000mb.c +++ b/drivers/media/dvb/frontends/dib3000mb.c @@ -60,8 +60,9 @@ static int dib3000mb_set_frontend(struct dvb_frontend* fe, fe_code_rate_t fe_cr = FEC_NONE; int search_state, seq; - if (tuner && state->config.pll_set) { - state->config.pll_set(fe, fep); + if (tuner && fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, fep); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); deb_setf("bandwidth: "); switch (ofdm->bandwidth) { @@ -386,9 +387,6 @@ static int dib3000mb_fe_init(struct dvb_frontend* fe, int mobile_mode) wr(DIB3000MB_REG_DATA_IN_DIVERSITY, DIB3000MB_DATA_DIVERSITY_IN_OFF); - if (state->config.pll_init) - state->config.pll_init(fe); - return 0; } @@ -707,7 +705,6 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, /* setup the state */ state->i2c = i2c; memcpy(&state->config,config,sizeof(struct dib3000_config)); - memcpy(&state->ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops)); /* check for the correct demod */ if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM) @@ -717,7 +714,7 @@ struct dvb_frontend* dib3000mb_attach(const struct dib3000_config* config, goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &dib3000mb_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; /* set the xfer operations */ diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c index 3b303dbb615..6c3be252998 100644 --- a/drivers/media/dvb/frontends/dib3000mc.c +++ b/drivers/media/dvb/frontends/dib3000mc.c @@ -462,8 +462,9 @@ static int dib3000mc_set_frontend(struct dvb_frontend* fe, int search_state,auto_val; u16 val; - if (tuner && state->config.pll_set) { /* initial call from dvb */ - state->config.pll_set(fe,fep); + if (tuner && fe->ops.tuner_ops.set_params) { /* initial call from dvb */ + fe->ops.tuner_ops.set_params(fe, fep); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); state->last_tuned_freq = fep->frequency; // if (!scanboost) { @@ -642,9 +643,6 @@ static int dib3000mc_fe_init(struct dvb_frontend* fe, int mobile_mode) set_or(DIB3000MC_REG_CLK_CFG_7,DIB3000MC_CLK_CFG_7_DIV_IN_OFF); - if (state->config.pll_init) - state->config.pll_init(fe); - deb_info("init end\n"); return 0; } @@ -839,7 +837,6 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, /* setup the state */ state->i2c = i2c; memcpy(&state->config,config,sizeof(struct dib3000_config)); - memcpy(&state->ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops)); /* check for the correct demod */ if (rd(DIB3000_REG_MANUFACTOR_ID) != DIB3000_I2C_ID_DIBCOM) @@ -859,7 +856,7 @@ struct dvb_frontend* dib3000mc_attach(const struct dib3000_config* config, } /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &dib3000mc_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; /* set the xfer operations */ @@ -876,6 +873,7 @@ error: kfree(state); return NULL; } +EXPORT_SYMBOL(dib3000mc_attach); static struct dvb_frontend_ops dib3000mc_ops = { @@ -914,5 +912,3 @@ static struct dvb_frontend_ops dib3000mc_ops = { MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); MODULE_LICENSE("GPL"); - -EXPORT_SYMBOL(dib3000mc_attach); diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c index 791706ec1da..a189683454b 100644 --- a/drivers/media/dvb/frontends/dvb-pll.c +++ b/drivers/media/dvb/frontends/dvb-pll.c @@ -227,10 +227,10 @@ struct dvb_pll_desc dvb_pll_tua6034 = { EXPORT_SYMBOL(dvb_pll_tua6034); /* Infineon TUA6034 - * used in LG TDVS H061F and LG TDVS H062F + * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F */ -struct dvb_pll_desc dvb_pll_tdvs_tua6034 = { - .name = "LG/Infineon TUA6034", +struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = { + .name = "LG TDVS-H06xF", .min = 54000000, .max = 863000000, .count = 3, @@ -240,7 +240,7 @@ struct dvb_pll_desc dvb_pll_tdvs_tua6034 = { { 999999999, 44000000, 62500, 0xce, 0x04 }, }, }; -EXPORT_SYMBOL(dvb_pll_tdvs_tua6034); +EXPORT_SYMBOL(dvb_pll_lg_tdvs_h06xf); /* Philips FMD1216ME * used in Medion Hybrid PCMCIA card and USB Box @@ -419,6 +419,19 @@ struct dvb_pll_desc dvb_pll_thomson_fe6600 = { }; EXPORT_SYMBOL(dvb_pll_thomson_fe6600); +struct dvb_pll_priv { + /* i2c details */ + int pll_i2c_address; + struct i2c_adapter *i2c; + + /* the PLL descriptor */ + struct dvb_pll_desc *pll_desc; + + /* cached frequency/bandwidth */ + u32 frequency; + u32 bandwidth; +}; + /* ----------------------------------------------------------- */ /* code */ @@ -443,7 +456,8 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, if (debug) printk("pll: %s: freq=%d bw=%d | i=%d/%d\n", desc->name, freq, bandwidth, i, desc->count); - BUG_ON(i == desc->count); + if (i == desc->count) + return -EINVAL; div = (freq + desc->entries[i].offset) / desc->entries[i].stepsize; buf[0] = div >> 8; @@ -462,6 +476,163 @@ int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, } EXPORT_SYMBOL(dvb_pll_configure); +static int dvb_pll_release(struct dvb_frontend *fe) +{ + if (fe->tuner_priv) + kfree(fe->tuner_priv); + fe->tuner_priv = NULL; + return 0; +} + +static int dvb_pll_sleep(struct dvb_frontend *fe) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + u8 buf[4]; + struct i2c_msg msg = + { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) }; + int i; + int result; + + for (i = 0; i < priv->pll_desc->count; i++) { + if (priv->pll_desc->entries[i].limit == 0) + break; + } + if (i == priv->pll_desc->count) + return 0; + + buf[0] = 0; + buf[1] = 0; + buf[2] = priv->pll_desc->entries[i].config; + buf[3] = priv->pll_desc->entries[i].cb; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { + return result; + } + + return 0; +} + +static int dvb_pll_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + u8 buf[4]; + struct i2c_msg msg = + { .addr = priv->pll_i2c_address, .flags = 0, .buf = buf, .len = sizeof(buf) }; + int result; + u32 div; + int i; + u32 bandwidth = 0; + + if (priv->i2c == NULL) + return -EINVAL; + + // DVBT bandwidth only just now + if (fe->ops.info.type == FE_OFDM) { + bandwidth = params->u.ofdm.bandwidth; + } + + if ((result = dvb_pll_configure(priv->pll_desc, buf, params->frequency, bandwidth)) != 0) + return result; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((result = i2c_transfer(priv->i2c, &msg, 1)) != 1) { + return result; + } + + // calculate the frequency we set it to + for (i = 0; i < priv->pll_desc->count; i++) { + if (params->frequency > priv->pll_desc->entries[i].limit) + continue; + break; + } + div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize; + priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset; + priv->bandwidth = bandwidth; + + return 0; +} + +static int dvb_pll_calc_regs(struct dvb_frontend *fe, struct dvb_frontend_parameters *params, u8 *buf, int buf_len) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + int result; + u32 div; + int i; + u32 bandwidth = 0; + + if (buf_len < 5) + return -EINVAL; + + // DVBT bandwidth only just now + if (fe->ops.info.type == FE_OFDM) { + bandwidth = params->u.ofdm.bandwidth; + } + + if ((result = dvb_pll_configure(priv->pll_desc, buf+1, params->frequency, bandwidth)) != 0) + return result; + buf[0] = priv->pll_i2c_address; + + // calculate the frequency we set it to + for (i = 0; i < priv->pll_desc->count; i++) { + if (params->frequency > priv->pll_desc->entries[i].limit) + continue; + break; + } + div = (params->frequency + priv->pll_desc->entries[i].offset) / priv->pll_desc->entries[i].stepsize; + priv->frequency = (div * priv->pll_desc->entries[i].stepsize) - priv->pll_desc->entries[i].offset; + priv->bandwidth = bandwidth; + + return 5; +} + +static int dvb_pll_get_frequency(struct dvb_frontend *fe, u32 *frequency) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + *frequency = priv->frequency; + return 0; +} + +static int dvb_pll_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) +{ + struct dvb_pll_priv *priv = fe->tuner_priv; + *bandwidth = priv->bandwidth; + return 0; +} + +static struct dvb_tuner_ops dvb_pll_tuner_ops = { + .release = dvb_pll_release, + .sleep = dvb_pll_sleep, + .set_params = dvb_pll_set_params, + .calc_regs = dvb_pll_calc_regs, + .get_frequency = dvb_pll_get_frequency, + .get_bandwidth = dvb_pll_get_bandwidth, +}; + +int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc) +{ + struct dvb_pll_priv *priv = NULL; + + priv = kzalloc(sizeof(struct dvb_pll_priv), GFP_KERNEL); + if (priv == NULL) + return -ENOMEM; + + priv->pll_i2c_address = pll_addr; + priv->i2c = i2c; + priv->pll_desc = desc; + + memcpy(&fe->ops.tuner_ops, &dvb_pll_tuner_ops, sizeof(struct dvb_tuner_ops)); + strncpy(fe->ops.tuner_ops.info.name, desc->name, 128); + fe->ops.tuner_ops.info.frequency_min = desc->min; + fe->ops.tuner_ops.info.frequency_min = desc->max; + + fe->tuner_priv = priv; + return 0; +} +EXPORT_SYMBOL(dvb_pll_attach); + MODULE_DESCRIPTION("dvb pll library"); MODULE_AUTHOR("Gerd Knorr"); MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h index 2b846178498..66361cd1880 100644 --- a/drivers/media/dvb/frontends/dvb-pll.h +++ b/drivers/media/dvb/frontends/dvb-pll.h @@ -5,6 +5,9 @@ #ifndef __DVB_PLL_H__ #define __DVB_PLL_H__ +#include <linux/i2c.h> +#include "dvb_frontend.h" + struct dvb_pll_desc { char *name; u32 min; @@ -31,7 +34,7 @@ extern struct dvb_pll_desc dvb_pll_unknown_1; extern struct dvb_pll_desc dvb_pll_tua6010xs; extern struct dvb_pll_desc dvb_pll_env57h1xd5; extern struct dvb_pll_desc dvb_pll_tua6034; -extern struct dvb_pll_desc dvb_pll_tdvs_tua6034; +extern struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf; extern struct dvb_pll_desc dvb_pll_tda665x; extern struct dvb_pll_desc dvb_pll_fmd1216me; extern struct dvb_pll_desc dvb_pll_tded4; @@ -44,7 +47,18 @@ extern struct dvb_pll_desc dvb_pll_philips_td1316; extern struct dvb_pll_desc dvb_pll_thomson_fe6600; -int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, +extern int dvb_pll_configure(struct dvb_pll_desc *desc, u8 *buf, u32 freq, int bandwidth); +/** + * Attach a dvb-pll to the supplied frontend structure. + * + * @param fe Frontend to attach to. + * @param pll_addr i2c address of the PLL (if used). + * @param i2c i2c adapter to use (set to NULL if not used). + * @param desc dvb_pll_desc to use. + * @return 0 on success, nonzero on failure. + */ +extern int dvb_pll_attach(struct dvb_frontend *fe, int pll_addr, struct i2c_adapter *i2c, struct dvb_pll_desc *desc); + #endif diff --git a/drivers/media/dvb/frontends/dvb_dummy_fe.c b/drivers/media/dvb/frontends/dvb_dummy_fe.c index 645946a992d..6271b1e7f6a 100644 --- a/drivers/media/dvb/frontends/dvb_dummy_fe.c +++ b/drivers/media/dvb/frontends/dvb_dummy_fe.c @@ -30,7 +30,6 @@ struct dvb_dummy_fe_state { - struct dvb_frontend_ops ops; struct dvb_frontend frontend; }; @@ -77,6 +76,11 @@ static int dvb_dummy_fe_get_frontend(struct dvb_frontend* fe, struct dvb_fronten static int dvb_dummy_fe_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { + if (fe->ops->tuner_ops->set_params) { + fe->ops->tuner_ops->set_params(fe, p); + if (fe->ops->i2c_gate_ctrl) fe->ops->i2c_gate_ctrl(fe, 0); + } + return 0; } @@ -116,11 +120,8 @@ struct dvb_frontend* dvb_dummy_fe_ofdm_attach(void) state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); if (state == NULL) goto error; - /* setup the state */ - memcpy(&state->ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops)); - /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &dvb_dummy_fe_ofdm_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -139,11 +140,8 @@ struct dvb_frontend* dvb_dummy_fe_qpsk_attach() state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); if (state == NULL) goto error; - /* setup the state */ - memcpy(&state->ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops)); - /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &dvb_dummy_fe_qpsk_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -162,11 +160,8 @@ struct dvb_frontend* dvb_dummy_fe_qam_attach() state = kmalloc(sizeof(struct dvb_dummy_fe_state), GFP_KERNEL); if (state == NULL) goto error; - /* setup the state */ - memcpy(&state->ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops)); - /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &dvb_dummy_fe_qam_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; diff --git a/drivers/media/dvb/frontends/isl6421.c b/drivers/media/dvb/frontends/isl6421.c new file mode 100644 index 00000000000..58c34db3107 --- /dev/null +++ b/drivers/media/dvb/frontends/isl6421.c @@ -0,0 +1,149 @@ +/* + * isl6421.h - driver for lnb supply and control ic ISL6421 + * + * Copyright (C) 2006 Andrew de Quincey + * Copyright (C) 2006 Oliver Endriss + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/string.h> +#include <linux/slab.h> + +#include "dvb_frontend.h" +#include "isl6421.h" + +struct isl6421 { + u8 config; + u8 override_or; + u8 override_and; + struct i2c_adapter *i2c; + u8 i2c_addr; + void (*release_chain)(struct dvb_frontend* fe); +}; + +static int isl6421_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv; + struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, + .buf = &isl6421->config, + .len = sizeof(isl6421->config) }; + + isl6421->config &= ~(ISL6421_VSEL1 | ISL6421_EN1); + + switch(voltage) { + case SEC_VOLTAGE_OFF: + break; + case SEC_VOLTAGE_13: + isl6421->config |= ISL6421_EN1; + break; + case SEC_VOLTAGE_18: + isl6421->config |= (ISL6421_EN1 | ISL6421_VSEL1); + break; + default: + return -EINVAL; + }; + + isl6421->config |= isl6421->override_or; + isl6421->config &= isl6421->override_and; + + return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static int isl6421_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) +{ + struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv; + struct i2c_msg msg = { .addr = isl6421->i2c_addr, .flags = 0, + .buf = &isl6421->config, + .len = sizeof(isl6421->config) }; + + if (arg) + isl6421->config |= ISL6421_LLC1; + else + isl6421->config &= ~ISL6421_LLC1; + + isl6421->config |= isl6421->override_or; + isl6421->config &= isl6421->override_and; + + return (i2c_transfer(isl6421->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static void isl6421_release(struct dvb_frontend *fe) +{ + struct isl6421 *isl6421 = (struct isl6421 *) fe->misc_priv; + + /* power off */ + isl6421_set_voltage(fe, SEC_VOLTAGE_OFF); + + /* free data & call next release routine */ + fe->ops.release = isl6421->release_chain; + kfree(fe->misc_priv); + fe->misc_priv = NULL; + if (fe->ops.release) + fe->ops.release(fe); +} + +int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, + u8 override_set, u8 override_clear) +{ + struct isl6421 *isl6421 = kmalloc(sizeof(struct isl6421), GFP_KERNEL); + if (!isl6421) + return -ENOMEM; + + /* default configuration */ + isl6421->config = ISL6421_ISEL1; + isl6421->i2c = i2c; + isl6421->i2c_addr = i2c_addr; + fe->misc_priv = isl6421; + + /* bits which should be forced to '1' */ + isl6421->override_or = override_set; + + /* bits which should be forced to '0' */ + isl6421->override_and = ~override_clear; + + /* detect if it is present or not */ + if (isl6421_set_voltage(fe, SEC_VOLTAGE_OFF)) { + kfree(isl6421); + fe->misc_priv = NULL; + return -EIO; + } + + /* install release callback */ + isl6421->release_chain = fe->ops.release; + fe->ops.release = isl6421_release; + + /* override frontend ops */ + fe->ops.set_voltage = isl6421_set_voltage; + fe->ops.enable_high_lnb_voltage = isl6421_enable_high_lnb_voltage; + + return 0; +} +EXPORT_SYMBOL(isl6421_attach); + +MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6421"); +MODULE_AUTHOR("Andrew de Quincey & Oliver Endriss"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/isl6421.h b/drivers/media/dvb/frontends/isl6421.h new file mode 100644 index 00000000000..675f80a19b9 --- /dev/null +++ b/drivers/media/dvb/frontends/isl6421.h @@ -0,0 +1,46 @@ +/* + * isl6421.h - driver for lnb supply and control ic ISL6421 + * + * Copyright (C) 2006 Andrew de Quincey + * Copyright (C) 2006 Oliver Endriss + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ + +#ifndef _ISL6421_H +#define _ISL6421_H + +#include <linux/dvb/frontend.h> + +/* system register bits */ +#define ISL6421_OLF1 0x01 +#define ISL6421_EN1 0x02 +#define ISL6421_VSEL1 0x04 +#define ISL6421_LLC1 0x08 +#define ISL6421_ENT1 0x10 +#define ISL6421_ISEL1 0x20 +#define ISL6421_DCL 0x40 + +/* override_set and override_clear control which system register bits (above) to always set & clear */ +extern int isl6421_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 i2c_addr, + u8 override_set, u8 override_clear); + +#endif diff --git a/drivers/media/dvb/frontends/l64781.c b/drivers/media/dvb/frontends/l64781.c index 1c7c9122447..f3bc82e44a2 100644 --- a/drivers/media/dvb/frontends/l64781.c +++ b/drivers/media/dvb/frontends/l64781.c @@ -32,7 +32,6 @@ struct l64781_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; const struct l64781_config* config; struct dvb_frontend frontend; @@ -141,7 +140,10 @@ static int apply_frontend_param (struct dvb_frontend* fe, struct dvb_frontend_pa u8 val0x06; int bw = p->bandwidth - BANDWIDTH_8_MHZ; - state->config->pll_set(fe, param); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } if (param->inversion != INVERSION_ON && param->inversion != INVERSION_OFF) @@ -463,8 +465,6 @@ static int l64781_init(struct dvb_frontend* fe) /* Everything is two's complement, soft bit and CSI_OUT too */ l64781_writereg (state, 0x1e, 0x09); - if (state->config->pll_init) state->config->pll_init(fe); - /* delay a bit after first init attempt */ if (state->first) { state->first = 0; @@ -508,7 +508,6 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &l64781_ops, sizeof(struct dvb_frontend_ops)); state->first = 1; /** @@ -554,7 +553,7 @@ struct dvb_frontend* l64781_attach(const struct l64781_config* config, } /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &l64781_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; diff --git a/drivers/media/dvb/frontends/l64781.h b/drivers/media/dvb/frontends/l64781.h index 947f65f8746..83b8bc21027 100644 --- a/drivers/media/dvb/frontends/l64781.h +++ b/drivers/media/dvb/frontends/l64781.h @@ -29,10 +29,6 @@ struct l64781_config { /* the demodulator's i2c address */ u8 demod_address; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; diff --git a/drivers/media/dvb/frontends/lg_h06xf.h b/drivers/media/dvb/frontends/lg_h06xf.h new file mode 100644 index 00000000000..754d51d1112 --- /dev/null +++ b/drivers/media/dvb/frontends/lg_h06xf.h @@ -0,0 +1,64 @@ +/* + * lg_h06xf.h - ATSC Tuner support for LG TDVS-H06xF + * + * 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 _LG_H06XF_H_ +#define _LG_H06XF_H_ +#include "dvb-pll.h" + +static int lg_h06xf_pll_set(struct dvb_frontend* fe, struct i2c_adapter* i2c_adap, + struct dvb_frontend_parameters* params) +{ + u8 buf[4]; + struct i2c_msg msg = { .addr = 0x61, .flags = 0, + .buf = buf, .len = sizeof(buf) }; + int err; + + dvb_pll_configure(&dvb_pll_lg_tdvs_h06xf, buf, params->frequency, 0); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) { + printk(KERN_WARNING "lg_h06xf: %s error " + "(addr %02x <- %02x, err = %i)\n", + __FUNCTION__, buf[0], buf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + /* Set the Auxiliary Byte. */ + buf[0] = buf[2]; + buf[0] &= ~0x20; + buf[0] |= 0x18; + buf[1] = 0x50; + msg.len = 2; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if ((err = i2c_transfer(i2c_adap, &msg, 1)) != 1) { + printk(KERN_WARNING "lg_h06xf: %s error " + "(addr %02x <- %02x, err = %i)\n", + __FUNCTION__, buf[0], buf[1], err); + if (err < 0) + return err; + else + return -EREMOTEIO; + } + + return 0; +} +#endif diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c index 4691ac54bc1..6e8ad176e1a 100644 --- a/drivers/media/dvb/frontends/lgdt330x.c +++ b/drivers/media/dvb/frontends/lgdt330x.c @@ -29,6 +29,7 @@ * DViCO FusionHDTV 5 Lite * DViCO FusionHDTV 5 USB Gold * Air2PC/AirStar 2 ATSC 3rd generation (HD5000) + * pcHDTV HD5500 * * TODO: * signal strength always returns 0. @@ -59,7 +60,6 @@ if (debug) printk(KERN_DEBUG "lgdt330x: " args); \ struct lgdt330x_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; /* Configuration settings */ const struct lgdt330x_config* config; @@ -399,8 +399,10 @@ static int lgdt330x_set_parameters(struct dvb_frontend* fe, } /* Tune to the specified frequency */ - if (state->config->pll_set) - state->config->pll_set(fe, param); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } /* Keep track of the new frequency */ /* FIXME this is the wrong way to do this... */ @@ -672,6 +674,7 @@ static int lgdt3303_read_snr(struct dvb_frontend* fe, u16* snr) if (state->current_modulation == VSB_8) { + i2c_read_demod_bytes(state, 0x6e, buf, 5); /* Phase Tracker Mean-Square Error Register for VSB */ noise = ((buf[0] & 7) << 16) | (buf[3] << 8) | buf[4]; } else { @@ -721,16 +724,19 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, /* Setup the state */ state->config = config; state->i2c = i2c; + + /* Create dvb_frontend */ switch (config->demod_chip) { case LGDT3302: - memcpy(&state->ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &lgdt3302_ops, sizeof(struct dvb_frontend_ops)); break; case LGDT3303: - memcpy(&state->ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops)); + memcpy(&state->frontend.ops, &lgdt3303_ops, sizeof(struct dvb_frontend_ops)); break; default: goto error; } + state->frontend.demodulator_priv = state; /* Verify communication with demod chip */ if (i2c_read_demod_bytes(state, 2, buf, 1)) @@ -739,9 +745,6 @@ struct dvb_frontend* lgdt330x_attach(const struct lgdt330x_config* config, state->current_frequency = -1; state->current_modulation = -1; - /* Create dvb_frontend */ - state->frontend.ops = &state->ops; - state->frontend.demodulator_priv = state; return &state->frontend; error: diff --git a/drivers/media/dvb/frontends/lgdt330x.h b/drivers/media/dvb/frontends/lgdt330x.h index 2a6529cccf1..bad903c6f0f 100644 --- a/drivers/media/dvb/frontends/lgdt330x.h +++ b/drivers/media/dvb/frontends/lgdt330x.h @@ -43,7 +43,6 @@ struct lgdt330x_config /* PLL interface */ int (*pll_rf_set) (struct dvb_frontend* fe, int index); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); /* Need to set device param for start_dma */ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); diff --git a/drivers/media/dvb/frontends/lnbp21.c b/drivers/media/dvb/frontends/lnbp21.c new file mode 100644 index 00000000000..e933edc8dd2 --- /dev/null +++ b/drivers/media/dvb/frontends/lnbp21.c @@ -0,0 +1,145 @@ +/* + * lnbp21.h - driver for lnb supply and control ic lnbp21 + * + * Copyright (C) 2006 Oliver Endriss + * + * 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + * + * + * the project's page is at http://www.linuxtv.org + */ +#include <linux/delay.h> +#include <linux/errno.h> +#include <linux/init.h> +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/moduleparam.h> +#include <linux/string.h> +#include <linux/slab.h> + +#include "dvb_frontend.h" +#include "lnbp21.h" + +struct lnbp21 { + u8 config; + u8 override_or; + u8 override_and; + struct i2c_adapter *i2c; + void (*release_chain)(struct dvb_frontend* fe); +}; + +static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) +{ + struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv; + struct i2c_msg msg = { .addr = 0x08, .flags = 0, + .buf = &lnbp21->config, + .len = sizeof(lnbp21->config) }; + + lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN); + + switch(voltage) { + case SEC_VOLTAGE_OFF: + break; + case SEC_VOLTAGE_13: + lnbp21->config |= LNBP21_EN; + break; + case SEC_VOLTAGE_18: + lnbp21->config |= (LNBP21_EN | LNBP21_VSEL); + break; + default: + return -EINVAL; + }; + + lnbp21->config |= lnbp21->override_or; + lnbp21->config &= lnbp21->override_and; + + return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) +{ + struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv; + struct i2c_msg msg = { .addr = 0x08, .flags = 0, + .buf = &lnbp21->config, + .len = sizeof(lnbp21->config) }; + + if (arg) + lnbp21->config |= LNBP21_LLC; + else + lnbp21->config &= ~LNBP21_LLC; + + lnbp21->config |= lnbp21->override_or; + lnbp21->config &= lnbp21->override_and; + + return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; +} + +static void lnbp21_release(struct dvb_frontend *fe) +{ + struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv; + + /* LNBP power off */ + lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF); + + /* free data & call next release routine */ + fe->ops.release = lnbp21->release_chain; + kfree(fe->misc_priv); + fe->misc_priv = NULL; + if (fe->ops.release) + fe->ops.release(fe); +} + +int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear) +{ + struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL); + if (!lnbp21) + return -ENOMEM; + + /* default configuration */ + lnbp21->config = LNBP21_ISEL; + lnbp21->i2c = i2c; + fe->misc_priv = lnbp21; + + /* bits which should be forced to '1' */ + lnbp21->override_or = override_set; + + /* bits which should be forced to '0' */ + lnbp21->override_and = ~override_clear; + + /* detect if it is present or not */ + if (lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF)) { + kfree(lnbp21); + fe->misc_priv = NULL; + return -EIO; + } + + /* install release callback */ + lnbp21->release_chain = fe->ops.release; + fe->ops.release = lnbp21_release; + + /* override frontend ops */ + fe->ops.set_voltage = lnbp21_set_voltage; + fe->ops.enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; + + return 0; +} +EXPORT_SYMBOL(lnbp21_attach); + +MODULE_DESCRIPTION("Driver for lnb supply and control ic lnbp21"); +MODULE_AUTHOR("Oliver Endriss"); +MODULE_LICENSE("GPL"); diff --git a/drivers/media/dvb/frontends/lnbp21.h b/drivers/media/dvb/frontends/lnbp21.h index 0dcbe61b61b..047a4ab68c0 100644 --- a/drivers/media/dvb/frontends/lnbp21.h +++ b/drivers/media/dvb/frontends/lnbp21.h @@ -27,7 +27,7 @@ #ifndef _LNBP21_H #define _LNBP21_H -/* system register */ +/* system register bits */ #define LNBP21_OLF 0x01 #define LNBP21_OTF 0x02 #define LNBP21_EN 0x04 @@ -37,103 +37,9 @@ #define LNBP21_ISEL 0x40 #define LNBP21_PCL 0x80 -struct lnbp21 { - u8 config; - u8 override_or; - u8 override_and; - struct i2c_adapter *i2c; - void (*release_chain)(struct dvb_frontend* fe); -}; +#include <linux/dvb/frontend.h> -static int lnbp21_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage) -{ - struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv; - struct i2c_msg msg = { .addr = 0x08, .flags = 0, - .buf = &lnbp21->config, - .len = sizeof(lnbp21->config) }; - - lnbp21->config &= ~(LNBP21_VSEL | LNBP21_EN); - - switch(voltage) { - case SEC_VOLTAGE_OFF: - break; - case SEC_VOLTAGE_13: - lnbp21->config |= LNBP21_EN; - break; - case SEC_VOLTAGE_18: - lnbp21->config |= (LNBP21_EN | LNBP21_VSEL); - break; - default: - return -EINVAL; - }; - - lnbp21->config |= lnbp21->override_or; - lnbp21->config &= lnbp21->override_and; - - return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; -} - -static int lnbp21_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) -{ - struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv; - struct i2c_msg msg = { .addr = 0x08, .flags = 0, - .buf = &lnbp21->config, - .len = sizeof(lnbp21->config) }; - - if (arg) - lnbp21->config |= LNBP21_LLC; - else - lnbp21->config &= ~LNBP21_LLC; - - lnbp21->config |= lnbp21->override_or; - lnbp21->config &= lnbp21->override_and; - - return (i2c_transfer(lnbp21->i2c, &msg, 1) == 1) ? 0 : -EIO; -} - -static void lnbp21_exit(struct dvb_frontend *fe) -{ - struct lnbp21 *lnbp21 = (struct lnbp21 *) fe->misc_priv; - - /* LNBP power off */ - lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF); - - /* free data & call next release routine */ - fe->ops->release = lnbp21->release_chain; - kfree(fe->misc_priv); - fe->misc_priv = NULL; - if (fe->ops->release) - fe->ops->release(fe); -} - -static int lnbp21_init(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear) -{ - struct lnbp21 *lnbp21 = kmalloc(sizeof(struct lnbp21), GFP_KERNEL); - - if (!lnbp21) - return -ENOMEM; - - /* default configuration */ - lnbp21->config = LNBP21_ISEL; - - /* bits which should be forced to '1' */ - lnbp21->override_or = override_set; - - /* bits which should be forced to '0' */ - lnbp21->override_and = ~override_clear; - - /* install release callback */ - lnbp21->release_chain = fe->ops->release; - fe->ops->release = lnbp21_exit; - - /* override frontend ops */ - fe->ops->set_voltage = lnbp21_set_voltage; - fe->ops->enable_high_lnb_voltage = lnbp21_enable_high_lnb_voltage; - - lnbp21->i2c = i2c; - fe->misc_priv = lnbp21; - - return lnbp21_set_voltage(fe, SEC_VOLTAGE_OFF); -} +/* override_set and override_clear control which system register bits (above) to always set & clear */ +extern int lnbp21_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, u8 override_set, u8 override_clear); #endif diff --git a/drivers/media/dvb/frontends/mt312.c b/drivers/media/dvb/frontends/mt312.c index d3aea83cf21..1ef82182564 100644 --- a/drivers/media/dvb/frontends/mt312.c +++ b/drivers/media/dvb/frontends/mt312.c @@ -39,7 +39,6 @@ struct mt312_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; /* configuration settings */ const struct mt312_config* config; struct dvb_frontend frontend; @@ -277,12 +276,6 @@ static int mt312_initfe(struct dvb_frontend* fe) if ((ret = mt312_writereg(state, CS_SW_LIM, 0x69)) < 0) return ret; - if (state->config->pll_init) { - mt312_writereg(state, GPP_CTRL, 0x40); - state->config->pll_init(fe); - mt312_writereg(state, GPP_CTRL, 0x00); - } - return 0; } @@ -477,16 +470,16 @@ static int mt312_set_frontend(struct dvb_frontend* fe, dprintk("%s: Freq %d\n", __FUNCTION__, p->frequency); - if ((p->frequency < fe->ops->info.frequency_min) - || (p->frequency > fe->ops->info.frequency_max)) + if ((p->frequency < fe->ops.info.frequency_min) + || (p->frequency > fe->ops.info.frequency_max)) return -EINVAL; if ((p->inversion < INVERSION_OFF) || (p->inversion > INVERSION_ON)) return -EINVAL; - if ((p->u.qpsk.symbol_rate < fe->ops->info.symbol_rate_min) - || (p->u.qpsk.symbol_rate > fe->ops->info.symbol_rate_max)) + if ((p->u.qpsk.symbol_rate < fe->ops.info.symbol_rate_min) + || (p->u.qpsk.symbol_rate > fe->ops.info.symbol_rate_max)) return -EINVAL; if ((p->u.qpsk.fec_inner < FEC_NONE) @@ -529,9 +522,10 @@ static int mt312_set_frontend(struct dvb_frontend* fe, return -EINVAL; } - mt312_writereg(state, GPP_CTRL, 0x40); - state->config->pll_set(fe, p); - mt312_writereg(state, GPP_CTRL, 0x00); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } /* sr = (u16)(sr * 256.0 / 1000000.0) */ sr = mt312_div(p->u.qpsk.symbol_rate * 4, 15625); @@ -578,6 +572,17 @@ static int mt312_get_frontend(struct dvb_frontend* fe, return 0; } +static int mt312_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct mt312_state* state = fe->demodulator_priv; + + if (enable) { + return mt312_writereg(state, GPP_CTRL, 0x40); + } else { + return mt312_writereg(state, GPP_CTRL, 0x00); + } +} + static int mt312_sleep(struct dvb_frontend* fe) { struct mt312_state *state = fe->demodulator_priv; @@ -633,6 +638,7 @@ static struct dvb_frontend_ops vp310_mt312_ops = { .init = mt312_initfe, .sleep = mt312_sleep, + .i2c_gate_ctrl = mt312_i2c_gate_ctrl, .set_frontend = mt312_set_frontend, .get_frontend = mt312_get_frontend, @@ -663,19 +669,22 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops)); /* check if the demod is there */ if (mt312_readreg(state, ID, &state->id) < 0) goto error; + /* create dvb_frontend */ + memcpy(&state->frontend.ops, &vp310_mt312_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.demodulator_priv = state; + switch (state->id) { case ID_VP310: - strcpy(state->ops.info.name, "Zarlink VP310 DVB-S"); + strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S"); state->frequency = 90; break; case ID_MT312: - strcpy(state->ops.info.name, "Zarlink MT312 DVB-S"); + strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S"); state->frequency = 60; break; default: @@ -683,9 +692,6 @@ struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, goto error; } - /* create dvb_frontend */ - state->frontend.ops = &state->ops; - state->frontend.demodulator_priv = state; return &state->frontend; error: diff --git a/drivers/media/dvb/frontends/mt312.h b/drivers/media/dvb/frontends/mt312.h index 074d844f013..666a1bd1c24 100644 --- a/drivers/media/dvb/frontends/mt312.h +++ b/drivers/media/dvb/frontends/mt312.h @@ -32,10 +32,6 @@ struct mt312_config { /* the demodulator's i2c address */ u8 demod_address; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; struct dvb_frontend* vp310_mt312_attach(const struct mt312_config* config, diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c index aaaec909ddf..5de7376c94c 100644 --- a/drivers/media/dvb/frontends/mt352.c +++ b/drivers/media/dvb/frontends/mt352.c @@ -45,7 +45,6 @@ struct mt352_state { struct i2c_adapter* i2c; struct dvb_frontend frontend; - struct dvb_frontend_ops ops; /* configuration settings */ struct mt352_config config; @@ -286,16 +285,25 @@ static int mt352_set_parameters(struct dvb_frontend* fe, mt352_calc_nominal_rate(state, op->bandwidth, buf+4); mt352_calc_input_freq(state, buf+6); - state->config.pll_set(fe, param, buf+8); - mt352_write(fe, buf, sizeof(buf)); if (state->config.no_tuner) { - /* start decoding */ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 0); + } + + mt352_write(fe, buf, 8); mt352_write(fe, fsm_go, 2); } else { - /* start tuning */ - mt352_write(fe, tuner_go, 2); + if (fe->ops.tuner_ops.calc_regs) { + fe->ops.tuner_ops.calc_regs(fe, param, buf+8, 5); + buf[8] <<= 1; + mt352_write(fe, buf, sizeof(buf)); + mt352_write(fe, tuner_go, 2); + } } + return 0; } @@ -541,13 +549,12 @@ struct dvb_frontend* mt352_attach(const struct mt352_config* config, /* setup the state */ state->i2c = i2c; memcpy(&state->config,config,sizeof(struct mt352_config)); - memcpy(&state->ops, &mt352_ops, sizeof(struct dvb_frontend_ops)); /* check if the demod is there */ if (mt352_read_register(state, CHIP_ID) != ID_MT352) goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &mt352_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h index 03040cd595b..9e7ff4b8fe5 100644 --- a/drivers/media/dvb/frontends/mt352.h +++ b/drivers/media/dvb/frontends/mt352.h @@ -49,12 +49,6 @@ struct mt352_config /* Initialise the demodulator and PLL. Cannot be NULL */ int (*demod_init)(struct dvb_frontend* fe); - - /* PLL setup - fill out the supplied 5 byte buffer with your PLL settings. - * byte0: Set to pll i2c address (nonlinux; left shifted by 1) - * byte1-4: PLL configuration. - */ - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u8* pllbuf); }; extern struct dvb_frontend* mt352_attach(const struct mt352_config* config, diff --git a/drivers/media/dvb/frontends/nxt200x.c b/drivers/media/dvb/frontends/nxt200x.c index 9e353539450..55671cb5255 100644 --- a/drivers/media/dvb/frontends/nxt200x.c +++ b/drivers/media/dvb/frontends/nxt200x.c @@ -55,7 +55,6 @@ struct nxt200x_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; const struct nxt200x_config* config; struct dvb_frontend frontend; @@ -333,17 +332,17 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data) dprintk("%s\n", __FUNCTION__); - dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[0], data[1], data[2], data[3]); + dprintk("Tuner Bytes: %02X %02X %02X %02X\n", data[1], data[2], data[3], data[4]); /* if NXT2004, write directly to tuner. if NXT2002, write through NXT chip. * direct write is required for Philips TUV1236D and ALPS TDHU2 */ switch (state->demod_chip) { case NXT2004: - if (i2c_writebytes(state, state->config->pll_address, data, 4)) + if (i2c_writebytes(state, data[0], data+1, 4)) printk(KERN_WARNING "nxt200x: error writing to tuner\n"); /* wait until we have a lock */ while (count < 20) { - i2c_readbytes(state, state->config->pll_address, &buf, 1); + i2c_readbytes(state, data[0], &buf, 1); if (buf & 0x40) return 0; msleep(100); @@ -361,10 +360,10 @@ static int nxt200x_writetuner (struct nxt200x_state* state, u8* data) nxt200x_writebytes(state, 0x34, &buf, 1); /* write actual tuner bytes */ - nxt200x_writebytes(state, 0x36, data, 4); + nxt200x_writebytes(state, 0x36, data+1, 4); /* set tuner i2c address */ - buf = state->config->pll_address; + buf = data[0] << 1; nxt200x_writebytes(state, 0x35, &buf, 1); /* write UC Opmode to begin transfer */ @@ -534,7 +533,7 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, struct dvb_frontend_parameters *p) { struct nxt200x_state* state = fe->demodulator_priv; - u8 buf[4]; + u8 buf[5]; /* stop the micro first */ nxt200x_microcontroller_stop(state); @@ -548,7 +547,9 @@ static int nxt200x_setup_frontend_parameters (struct dvb_frontend* fe, } /* get tuning information */ - dvb_pll_configure(state->config->pll_desc, buf, p->frequency, 0); + if (fe->ops.tuner_ops.calc_regs) { + fe->ops.tuner_ops.calc_regs(fe, p, buf, 5); + } /* set additional params */ switch (p->u.vsb.modulation) { @@ -1159,7 +1160,6 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops)); state->initialised = 0; /* read card id */ @@ -1198,7 +1198,7 @@ struct dvb_frontend* nxt200x_attach(const struct nxt200x_config* config, } /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &nxt200x_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; diff --git a/drivers/media/dvb/frontends/nxt200x.h b/drivers/media/dvb/frontends/nxt200x.h index 1d9d70bc37e..34d61735845 100644 --- a/drivers/media/dvb/frontends/nxt200x.h +++ b/drivers/media/dvb/frontends/nxt200x.h @@ -38,10 +38,6 @@ struct nxt200x_config /* the demodulator's i2c address */ u8 demod_address; - /* tuner information */ - u8 pll_address; - struct dvb_pll_desc *pll_desc; - /* used to set pll input */ int (*set_pll_input)(u8* buf, int input); diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c index a16eeba0020..d313d7dcf38 100644 --- a/drivers/media/dvb/frontends/nxt6000.c +++ b/drivers/media/dvb/frontends/nxt6000.c @@ -33,7 +33,6 @@ struct nxt6000_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; /* configuration settings */ const struct nxt6000_config* config; struct dvb_frontend frontend; @@ -207,12 +206,6 @@ static void nxt6000_setup(struct dvb_frontend* fe) nxt6000_writereg(state, SUB_DIAG_MODE_SEL, 0); nxt6000_writereg(state, TS_FORMAT, 0); - - if (state->config->pll_init) { - nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */ - state->config->pll_init(fe); - nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */ - } } static void nxt6000_dump_status(struct nxt6000_state *state) @@ -469,9 +462,10 @@ static int nxt6000_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par struct nxt6000_state* state = fe->demodulator_priv; int result; - nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); /* open i2c bus switch */ - state->config->pll_set(fe, param); - nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); /* close i2c bus switch */ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } if ((result = nxt6000_set_bandwidth(state, param->u.ofdm.bandwidth)) < 0) return result; @@ -532,6 +526,17 @@ static int nxt6000_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_fron return 0; } +static int nxt6000_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct nxt6000_state* state = fe->demodulator_priv; + + if (enable) { + return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x01); + } else { + return nxt6000_writereg(state, ENABLE_TUNER_IIC, 0x00); + } +} + static struct dvb_frontend_ops nxt6000_ops; struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, @@ -546,13 +551,12 @@ struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops)); /* check if the demod is there */ if (nxt6000_readreg(state, OFDM_MSC_REV) != NXT6000ASICDEVICE) goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &nxt6000_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -584,6 +588,7 @@ static struct dvb_frontend_ops nxt6000_ops = { .release = nxt6000_release, .init = nxt6000_init, + .i2c_gate_ctrl = nxt6000_i2c_gate_ctrl, .get_tune_settings = nxt6000_fe_get_tune_settings, diff --git a/drivers/media/dvb/frontends/nxt6000.h b/drivers/media/dvb/frontends/nxt6000.h index b7d9bead300..117031d1170 100644 --- a/drivers/media/dvb/frontends/nxt6000.h +++ b/drivers/media/dvb/frontends/nxt6000.h @@ -31,10 +31,6 @@ struct nxt6000_config /* should clock inversion be used? */ u8 clock_inversion:1; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; extern struct dvb_frontend* nxt6000_attach(const struct nxt6000_config* config, diff --git a/drivers/media/dvb/frontends/or51132.c b/drivers/media/dvb/frontends/or51132.c index 80e0f28127b..d20ab30c1e8 100644 --- a/drivers/media/dvb/frontends/or51132.c +++ b/drivers/media/dvb/frontends/or51132.c @@ -54,7 +54,6 @@ static int debug; struct or51132_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; /* Configuration settings */ const struct or51132_config* config; @@ -106,9 +105,8 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware { struct or51132_state* state = fe->demodulator_priv; static u8 run_buf[] = {0x7F,0x01}; - static u8 get_ver_buf[] = {0x04,0x00,0x30,0x00,0x00}; - u8 rec_buf[14]; - u8 cmd_buf[14]; + u8 rec_buf[8]; + u8 cmd_buf[3]; u32 firmwareAsize, firmwareBsize; int i,ret; @@ -157,7 +155,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware cmd_buf[0] = 0x10; cmd_buf[1] = 0x10; cmd_buf[2] = 0x00; - cmd_buf[3] = 0x00; msleep(20); /* 20ms */ if ((ret = i2c_writebytes(state,state->config->demod_address, cmd_buf,3))) { @@ -167,8 +164,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware cmd_buf[0] = 0x04; cmd_buf[1] = 0x17; - cmd_buf[2] = 0x00; - cmd_buf[3] = 0x00; msleep(20); /* 20ms */ if ((ret = i2c_writebytes(state,state->config->demod_address, cmd_buf,2))) { @@ -178,8 +173,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware cmd_buf[0] = 0x00; cmd_buf[1] = 0x00; - cmd_buf[2] = 0x00; - cmd_buf[3] = 0x00; msleep(20); /* 20ms */ if ((ret = i2c_writebytes(state,state->config->demod_address, cmd_buf,2))) { @@ -189,7 +182,11 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware for(i=0;i<4;i++) { msleep(20); /* 20ms */ - get_ver_buf[4] = i+1; + /* Once upon a time, this command might have had something + to do with getting the firmware version, but it's + not used anymore: + {0x04,0x00,0x30,0x00,i+1} */ + /* Read 8 bytes, two bytes at a time */ if ((ret = i2c_readbytes(state,state->config->demod_address, &rec_buf[i*2],2))) { printk(KERN_WARNING @@ -208,7 +205,6 @@ static int or51132_load_firmware (struct dvb_frontend* fe, const struct firmware cmd_buf[0] = 0x10; cmd_buf[1] = 0x00; cmd_buf[2] = 0x00; - cmd_buf[3] = 0x00; msleep(20); /* 20ms */ if ((ret = i2c_writebytes(state,state->config->demod_address, cmd_buf,3))) { @@ -243,7 +239,7 @@ static int or51132_sleep(struct dvb_frontend* fe) static int or51132_setmode(struct dvb_frontend* fe) { struct or51132_state* state = fe->demodulator_priv; - unsigned char cmd_buf[4]; + unsigned char cmd_buf[3]; dprintk("setmode %d\n",(int)state->current_modulation); /* set operation mode in Receiver 1 register; */ @@ -263,7 +259,6 @@ static int or51132_setmode(struct dvb_frontend* fe) default: printk("setmode:Modulation set to unsupported value\n"); }; - cmd_buf[3] = 0x00; if (i2c_writebytes(state,state->config->demod_address, cmd_buf,3)) { printk(KERN_WARNING "or51132: set_mode error 1\n"); @@ -301,7 +296,6 @@ static int or51132_setmode(struct dvb_frontend* fe) default: printk("setmode: Modulation set to unsupported value\n"); }; - cmd_buf[3] = 0x00; msleep(20); /* 20ms */ if (i2c_writebytes(state,state->config->demod_address, cmd_buf,3)) { @@ -313,52 +307,65 @@ static int or51132_setmode(struct dvb_frontend* fe) return 0; } +/* Some modulations use the same firmware. This classifies modulations + by the firmware they use. */ +#define MOD_FWCLASS_UNKNOWN 0 +#define MOD_FWCLASS_VSB 1 +#define MOD_FWCLASS_QAM 2 +static int modulation_fw_class(fe_modulation_t modulation) +{ + switch(modulation) { + case VSB_8: + return MOD_FWCLASS_VSB; + case QAM_AUTO: + case QAM_64: + case QAM_256: + return MOD_FWCLASS_QAM; + default: + return MOD_FWCLASS_UNKNOWN; + } +} + static int or51132_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_parameters *param) { int ret; - u8 buf[4]; struct or51132_state* state = fe->demodulator_priv; const struct firmware *fw; - - /* Change only if we are actually changing the modulation */ - if (state->current_modulation != param->u.vsb.modulation) { - switch(param->u.vsb.modulation) { - case VSB_8: + const char *fwname; + int clock_mode; + + /* Upload new firmware only if we need a different one */ + if (modulation_fw_class(state->current_modulation) != + modulation_fw_class(param->u.vsb.modulation)) { + switch(modulation_fw_class(param->u.vsb.modulation)) { + case MOD_FWCLASS_VSB: dprintk("set_parameters VSB MODE\n"); - printk("or51132: Waiting for firmware upload(%s)...\n", - OR51132_VSB_FIRMWARE); - ret = request_firmware(&fw, OR51132_VSB_FIRMWARE, - &state->i2c->dev); - if (ret){ - printk(KERN_WARNING "or51132: No firmware up" - "loaded(timeout or file not found?)\n"); - return ret; - } + fwname = OR51132_VSB_FIRMWARE; + /* Set non-punctured clock for VSB */ - state->config->set_ts_params(fe, 0); + clock_mode = 0; break; - case QAM_AUTO: - case QAM_64: - case QAM_256: + case MOD_FWCLASS_QAM: dprintk("set_parameters QAM MODE\n"); - printk("or51132: Waiting for firmware upload(%s)...\n", - OR51132_QAM_FIRMWARE); - ret = request_firmware(&fw, OR51132_QAM_FIRMWARE, - &state->i2c->dev); - if (ret){ - printk(KERN_WARNING "or51132: No firmware up" - "loaded(timeout or file not found?)\n"); - return ret; - } + fwname = OR51132_QAM_FIRMWARE; + /* Set punctured clock for QAM */ - state->config->set_ts_params(fe, 1); + clock_mode = 1; break; default: - printk("or51132:Modulation type(%d) UNSUPPORTED\n", + printk("or51132: Modulation type(%d) UNSUPPORTED\n", param->u.vsb.modulation); return -1; - }; + } + printk("or51132: Waiting for firmware upload(%s)...\n", + fwname); + ret = request_firmware(&fw, fwname, &state->i2c->dev); + if (ret) { + printk(KERN_WARNING "or51132: No firmware up" + "loaded(timeout or file not found?)\n"); + return ret; + } ret = or51132_load_firmware(fe, fw); release_firmware(fw); if (ret) { @@ -367,18 +374,18 @@ static int or51132_set_parameters(struct dvb_frontend* fe, return ret; } printk("or51132: Firmware upload complete.\n"); - + state->config->set_ts_params(fe, clock_mode); + } + /* Change only if we are actually changing the modulation */ + if (state->current_modulation != param->u.vsb.modulation) { state->current_modulation = param->u.vsb.modulation; or51132_setmode(fe); } - dvb_pll_configure(state->config->pll_desc, buf, - param->frequency, 0); - dprintk("set_parameters tuner bytes: 0x%02x 0x%02x " - "0x%02x 0x%02x\n",buf[0],buf[1],buf[2],buf[3]); - if (i2c_writebytes(state, state->config->pll_address ,buf, 4)) - printk(KERN_WARNING "or51132: set_parameters error " - "writing to tuner\n"); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } /* Set to current mode */ or51132_setmode(fe); @@ -388,6 +395,44 @@ static int or51132_set_parameters(struct dvb_frontend* fe, return 0; } +static int or51132_get_parameters(struct dvb_frontend* fe, + struct dvb_frontend_parameters *param) +{ + struct or51132_state* state = fe->demodulator_priv; + u8 buf[2]; + + /* Receiver Status */ + buf[0]=0x04; + buf[1]=0x00; + msleep(30); /* 30ms */ + if (i2c_writebytes(state,state->config->demod_address,buf,2)) { + printk(KERN_WARNING "or51132: get_parameters write error\n"); + return -EREMOTEIO; + } + msleep(30); /* 30ms */ + if (i2c_readbytes(state,state->config->demod_address,buf,2)) { + printk(KERN_WARNING "or51132: get_parameters read error\n"); + return -EREMOTEIO; + } + switch(buf[0]) { + case 0x06: param->u.vsb.modulation = VSB_8; break; + case 0x43: param->u.vsb.modulation = QAM_64; break; + case 0x45: param->u.vsb.modulation = QAM_256; break; + default: + printk(KERN_WARNING "or51132: unknown status 0x%02x\n", + buf[0]); + return -EREMOTEIO; + } + + /* FIXME: Read frequency from frontend, take AFC into account */ + param->frequency = state->current_frequency; + + /* FIXME: How to read inversion setting? Receiver 6 register? */ + param->inversion = INVERSION_AUTO; + + return 0; +} + static int or51132_read_status(struct dvb_frontend* fe, fe_status_t* status) { struct or51132_state* state = fe->demodulator_priv; @@ -572,12 +617,11 @@ struct dvb_frontend* or51132_attach(const struct or51132_config* config, /* Setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); state->current_frequency = -1; state->current_modulation = -1; /* Create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &or51132_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -590,7 +634,7 @@ static struct dvb_frontend_ops or51132_ops = { .info = { .name = "Oren OR51132 VSB/QAM Frontend", - .type = FE_ATSC, + .type = FE_ATSC, .frequency_min = 44000000, .frequency_max = 958000000, .frequency_stepsize = 166666, @@ -606,6 +650,7 @@ static struct dvb_frontend_ops or51132_ops = { .sleep = or51132_sleep, .set_frontend = or51132_set_parameters, + .get_frontend = or51132_get_parameters, .get_tune_settings = or51132_get_tune_settings, .read_status = or51132_read_status, diff --git a/drivers/media/dvb/frontends/or51132.h b/drivers/media/dvb/frontends/or51132.h index 622cdd18381..89658883abf 100644 --- a/drivers/media/dvb/frontends/or51132.h +++ b/drivers/media/dvb/frontends/or51132.h @@ -29,8 +29,6 @@ struct or51132_config { /* The demodulator's i2c address */ u8 demod_address; - u8 pll_address; - struct dvb_pll_desc *pll_desc; /* Need to set device param for start_dma */ int (*set_ts_params)(struct dvb_frontend* fe, int is_punctured); diff --git a/drivers/media/dvb/frontends/or51211.c b/drivers/media/dvb/frontends/or51211.c index 7c3aed1f546..26bed616fab 100644 --- a/drivers/media/dvb/frontends/or51211.c +++ b/drivers/media/dvb/frontends/or51211.c @@ -54,7 +54,6 @@ static u8 cmd_buf[] = {0x04,0x01,0x50,0x80,0x06}; // ATSC struct or51211_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; /* Configuration settings */ const struct or51211_config* config; @@ -585,12 +584,11 @@ struct dvb_frontend* or51211_attach(const struct or51211_config* config, /* Setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &or51211_ops, sizeof(struct dvb_frontend_ops)); state->initialized = 0; state->current_frequency = 0; /* Create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &or51211_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c index d6947759692..2c2c344c4c6 100644 --- a/drivers/media/dvb/frontends/s5h1420.c +++ b/drivers/media/dvb/frontends/s5h1420.c @@ -38,7 +38,6 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. struct s5h1420_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; const struct s5h1420_config* config; struct dvb_frontend frontend; @@ -584,7 +583,6 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, struct s5h1420_state* state = fe->demodulator_priv; int frequency_delta; struct dvb_frontend_tune_settings fesettings; - u32 tmp; /* check if we should do a fast-tune */ memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters)); @@ -596,10 +594,17 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, (state->fec_inner == p->u.qpsk.fec_inner) && (state->symbol_rate == p->u.qpsk.symbol_rate)) { - if (state->config->pll_set) { - s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); - state->config->pll_set(fe, p, &tmp); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + if (fe->ops.tuner_ops.get_frequency) { + u32 tmp; + fe->ops.tuner_ops.get_frequency(fe, &tmp); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); s5h1420_setfreqoffset(state, p->frequency - tmp); + } else { + s5h1420_setfreqoffset(state, 0); } return 0; } @@ -646,9 +651,9 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe, s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1); /* set tuner PLL */ - if (state->config->pll_set) { - s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); - state->config->pll_set(fe, p, &tmp); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); s5h1420_setfreqoffset(state, 0); } @@ -708,6 +713,17 @@ static int s5h1420_get_tune_settings(struct dvb_frontend* fe, return 0; } +static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct s5h1420_state* state = fe->demodulator_priv; + + if (enable) { + return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); + } else { + return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe); + } +} + static int s5h1420_init (struct dvb_frontend* fe) { struct s5h1420_state* state = fe->demodulator_priv; @@ -717,13 +733,6 @@ static int s5h1420_init (struct dvb_frontend* fe) msleep(10); s5h1420_reset(state); - /* init PLL */ - if (state->config->pll_init) { - s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1); - state->config->pll_init(fe); - s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe); - } - return 0; } @@ -756,7 +765,6 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops)); state->postlocked = 0; state->fclk = 88000000; state->tunedfreq = 0; @@ -769,7 +777,7 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -800,6 +808,7 @@ static struct dvb_frontend_ops s5h1420_ops = { .init = s5h1420_init, .sleep = s5h1420_sleep, + .i2c_gate_ctrl = s5h1420_i2c_gate_ctrl, .set_frontend = s5h1420_set_frontend, .get_frontend = s5h1420_get_frontend, diff --git a/drivers/media/dvb/frontends/s5h1420.h b/drivers/media/dvb/frontends/s5h1420.h index 73296f13c32..4e39015fa67 100644 --- a/drivers/media/dvb/frontends/s5h1420.h +++ b/drivers/media/dvb/frontends/s5h1420.h @@ -32,10 +32,6 @@ struct s5h1420_config /* does the inversion require inversion? */ u8 invert:1; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout); }; extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config, diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c index 73829e647e5..44ec5b9a469 100644 --- a/drivers/media/dvb/frontends/sp8870.c +++ b/drivers/media/dvb/frontends/sp8870.c @@ -44,8 +44,6 @@ struct sp8870_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; - const struct sp8870_config* config; struct dvb_frontend frontend; @@ -262,9 +260,10 @@ static int sp8870_set_frontend_parameters (struct dvb_frontend* fe, sp8870_microcontroller_stop(state); // set tuner parameters - sp8870_writereg(state, 0x206, 0x001); - state->config->pll_set(fe, p); - sp8870_writereg(state, 0x206, 0x000); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } // sample rate correction bit [23..17] sp8870_writereg(state, 0x0319, 0x000A); @@ -349,13 +348,6 @@ static int sp8870_init (struct dvb_frontend* fe) sp8870_writereg(state, 0x0D00, 0x010); sp8870_writereg(state, 0x0D01, 0x000); - /* setup PLL */ - if (state->config->pll_init) { - sp8870_writereg(state, 0x206, 0x001); - state->config->pll_init(fe); - sp8870_writereg(state, 0x206, 0x000); - } - return 0; } @@ -541,6 +533,17 @@ static int sp8870_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend return 0; } +static int sp8870_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct sp8870_state* state = fe->demodulator_priv; + + if (enable) { + return sp8870_writereg(state, 0x206, 0x001); + } else { + return sp8870_writereg(state, 0x206, 0x000); + } +} + static void sp8870_release(struct dvb_frontend* fe) { struct sp8870_state* state = fe->demodulator_priv; @@ -561,14 +564,13 @@ struct dvb_frontend* sp8870_attach(const struct sp8870_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &sp8870_ops, sizeof(struct dvb_frontend_ops)); state->initialised = 0; /* check if the demod is there */ if (sp8870_readreg(state, 0x0200) < 0) goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &sp8870_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -597,6 +599,7 @@ static struct dvb_frontend_ops sp8870_ops = { .init = sp8870_init, .sleep = sp8870_sleep, + .i2c_gate_ctrl = sp8870_i2c_gate_ctrl, .set_frontend = sp8870_set_frontend, .get_tune_settings = sp8870_get_tune_settings, diff --git a/drivers/media/dvb/frontends/sp8870.h b/drivers/media/dvb/frontends/sp8870.h index f3b555dbc96..93afbb969d6 100644 --- a/drivers/media/dvb/frontends/sp8870.h +++ b/drivers/media/dvb/frontends/sp8870.h @@ -31,10 +31,6 @@ struct sp8870_config /* the demodulator's i2c address */ u8 demod_address; - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - /* request firmware for device */ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; diff --git a/drivers/media/dvb/frontends/sp887x.c b/drivers/media/dvb/frontends/sp887x.c index eb8a602198c..b0a2b02f660 100644 --- a/drivers/media/dvb/frontends/sp887x.c +++ b/drivers/media/dvb/frontends/sp887x.c @@ -24,7 +24,6 @@ struct sp887x_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; const struct sp887x_config* config; struct dvb_frontend frontend; @@ -208,15 +207,6 @@ static int sp887x_initial_setup (struct dvb_frontend* fe, const struct firmware /* bit 0x010: enable data valid signal */ sp887x_writereg(state, 0xd00, 0x010); sp887x_writereg(state, 0x0d1, 0x000); - - /* setup the PLL */ - if (state->config->pll_init) { - sp887x_writereg(state, 0x206, 0x001); - state->config->pll_init(fe); - sp887x_writereg(state, 0x206, 0x000); - } - - printk ("done.\n"); return 0; }; @@ -362,9 +352,16 @@ static int sp887x_setup_frontend_parameters (struct dvb_frontend* fe, sp887x_microcontroller_stop(state); /* setup the PLL */ - sp887x_writereg(state, 0x206, 0x001); - actual_freq = state->config->pll_set(fe, p); - sp887x_writereg(state, 0x206, 0x000); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + if (fe->ops.tuner_ops.get_frequency) { + fe->ops.tuner_ops.get_frequency(fe, &actual_freq); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } else { + actual_freq = p->frequency; + } /* read status reg in order to clear <pending irqs */ sp887x_readreg(state, 0x200); @@ -486,6 +483,17 @@ static int sp887x_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks) return 0; } +static int sp887x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct sp887x_state* state = fe->demodulator_priv; + + if (enable) { + return sp887x_writereg(state, 0x206, 0x001); + } else { + return sp887x_writereg(state, 0x206, 0x000); + } +} + static int sp887x_sleep(struct dvb_frontend* fe) { struct sp887x_state* state = fe->demodulator_priv; @@ -555,14 +563,13 @@ struct dvb_frontend* sp887x_attach(const struct sp887x_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &sp887x_ops, sizeof(struct dvb_frontend_ops)); state->initialised = 0; /* check if the demod is there */ if (sp887x_readreg(state, 0x0200) < 0) goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &sp887x_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -589,6 +596,7 @@ static struct dvb_frontend_ops sp887x_ops = { .init = sp887x_init, .sleep = sp887x_sleep, + .i2c_gate_ctrl = sp887x_i2c_gate_ctrl, .set_frontend = sp887x_setup_frontend_parameters, .get_tune_settings = sp887x_get_tune_settings, diff --git a/drivers/media/dvb/frontends/sp887x.h b/drivers/media/dvb/frontends/sp887x.h index 6a05d8f8e8c..c44b0ebdf1e 100644 --- a/drivers/media/dvb/frontends/sp887x.h +++ b/drivers/media/dvb/frontends/sp887x.h @@ -13,12 +13,6 @@ struct sp887x_config /* the demodulator's i2c address */ u8 demod_address; - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - - /* this should return the actual frequency tuned to */ - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - /* request firmware for device */ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); }; diff --git a/drivers/media/dvb/frontends/stv0297.c b/drivers/media/dvb/frontends/stv0297.c index eb15676d374..1ca64249010 100644 --- a/drivers/media/dvb/frontends/stv0297.c +++ b/drivers/media/dvb/frontends/stv0297.c @@ -32,7 +32,6 @@ struct stv0297_state { struct i2c_adapter *i2c; - struct dvb_frontend_ops ops; const struct stv0297_config *config; struct dvb_frontend frontend; @@ -68,19 +67,25 @@ static int stv0297_readreg(struct stv0297_state *state, u8 reg) int ret; u8 b0[] = { reg }; u8 b1[] = { 0 }; - struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = - 1}, - {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} - }; + struct i2c_msg msg[] = { {.addr = state->config->demod_address,.flags = 0,.buf = b0,.len = 1}, + {.addr = state->config->demod_address,.flags = I2C_M_RD,.buf = b1,.len = 1} + }; // this device needs a STOP between the register and data - if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); - return -1; - } - if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); - return -1; + if (state->config->stop_during_read) { + if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); + return -1; + } + if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); + return -1; + } + } else { + if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg, ret); + return -1; + } } return b1[0]; @@ -107,13 +112,20 @@ static int stv0297_readregs(struct stv0297_state *state, u8 reg1, u8 * b, u8 len }; // this device needs a STOP between the register and data - if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); - return -1; - } - if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { - dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); - return -1; + if (state->config->stop_during_read) { + if ((ret = i2c_transfer(state->i2c, &msg[0], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); + return -1; + } + if ((ret = i2c_transfer(state->i2c, &msg[1], 1)) != 1) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); + return -1; + } + } else { + if ((ret = i2c_transfer(state->i2c, msg, 2)) != 2) { + dprintk("%s: readreg error (reg == 0x%02x, ret == %i)\n", __FUNCTION__, reg1, ret); + return -1; + } } return 0; @@ -276,12 +288,14 @@ static int stv0297_set_inversion(struct stv0297_state *state, fe_spectral_invers return 0; } -int stv0297_enable_plli2c(struct dvb_frontend *fe) +static int stv0297_i2c_gate_ctrl(struct dvb_frontend *fe, int enable) { struct stv0297_state *state = fe->demodulator_priv; - stv0297_writereg(state, 0x87, 0x78); - stv0297_writereg(state, 0x86, 0xc8); + if (enable) { + stv0297_writereg(state, 0x87, 0x78); + stv0297_writereg(state, 0x86, 0xc8); + } return 0; } @@ -296,9 +310,6 @@ static int stv0297_init(struct dvb_frontend *fe) stv0297_writereg(state, state->config->inittab[i], state->config->inittab[i+1]); msleep(200); - if (state->config->pll_init) - state->config->pll_init(fe); - return 0; } @@ -389,7 +400,7 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par case QAM_32: case QAM_64: delay = 100; - sweeprate = 1500; + sweeprate = 1000; break; case QAM_128: @@ -421,7 +432,10 @@ static int stv0297_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par } stv0297_init(fe); - state->config->pll_set(fe, p); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } /* clear software interrupts */ stv0297_writereg(state, 0x82, 0x0); @@ -634,7 +648,6 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); state->base_freq = 0; /* check if the demod is there */ @@ -642,7 +655,7 @@ struct dvb_frontend *stv0297_attach(const struct stv0297_config *config, goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &stv0297_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -668,6 +681,7 @@ static struct dvb_frontend_ops stv0297_ops = { .init = stv0297_init, .sleep = stv0297_sleep, + .i2c_gate_ctrl = stv0297_i2c_gate_ctrl, .set_frontend = stv0297_set_frontend, .get_frontend = stv0297_get_frontend, @@ -684,4 +698,3 @@ MODULE_AUTHOR("Dennis Noermann and Andrew de Quincey"); MODULE_LICENSE("GPL"); EXPORT_SYMBOL(stv0297_attach); -EXPORT_SYMBOL(stv0297_enable_plli2c); diff --git a/drivers/media/dvb/frontends/stv0297.h b/drivers/media/dvb/frontends/stv0297.h index 9e53f019db7..1da5384fb98 100644 --- a/drivers/media/dvb/frontends/stv0297.h +++ b/drivers/media/dvb/frontends/stv0297.h @@ -38,13 +38,11 @@ struct stv0297_config /* does the "inversion" need inverted? */ u8 invert:1; - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); + /* set to 1 if the device requires an i2c STOP during reading */ + u8 stop_during_read:1; }; extern struct dvb_frontend* stv0297_attach(const struct stv0297_config* config, struct i2c_adapter* i2c); -extern int stv0297_enable_plli2c(struct dvb_frontend* fe); #endif // STV0297_H diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c index 5bcd00f792e..96648a75440 100644 --- a/drivers/media/dvb/frontends/stv0299.c +++ b/drivers/media/dvb/frontends/stv0299.c @@ -56,7 +56,6 @@ struct stv0299_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; const struct stv0299_config* config; struct dvb_frontend frontend; @@ -131,13 +130,6 @@ static int stv0299_readregs (struct stv0299_state* state, u8 reg1, u8 *b, u8 len return ret == 2 ? 0 : ret; } -int stv0299_enable_plli2c (struct dvb_frontend* fe) -{ - struct stv0299_state* state = fe->demodulator_priv; - - return stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ -} - static int stv0299_set_FEC (struct stv0299_state* state, fe_code_rate_t fec) { dprintk ("%s\n", __FUNCTION__); @@ -457,12 +449,6 @@ static int stv0299_init (struct dvb_frontend* fe) for (i=0; !(state->config->inittab[i] == 0xff && state->config->inittab[i+1] == 0xff); i+=2) stv0299_writeregI(state, state->config->inittab[i], state->config->inittab[i+1]); - if (state->config->pll_init) { - stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_init(fe, state->i2c); - stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ - } - return 0; } @@ -560,9 +546,10 @@ static int stv0299_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par if (state->config->invert) invval = (~invval) & 1; stv0299_writeregI(state, 0x0c, (stv0299_readreg(state, 0x0c) & 0xfe) | invval); - stv0299_writeregI(state, 0x05, 0xb5); /* enable i2c repeater on stv0299 */ - state->config->pll_set(fe, state->i2c, p); - stv0299_writeregI(state, 0x05, 0x35); /* disable i2c repeater on stv0299 */ + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } stv0299_set_FEC (state, p->u.qpsk.fec_inner); stv0299_set_symbolrate (fe, p->u.qpsk.symbol_rate); @@ -611,6 +598,19 @@ static int stv0299_sleep(struct dvb_frontend* fe) return 0; } +static int stv0299_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct stv0299_state* state = fe->demodulator_priv; + + if (enable) { + stv0299_writeregI(state, 0x05, 0xb5); + } else { + stv0299_writeregI(state, 0x05, 0x35); + } + udelay(1); + return 0; +} + static int stv0299_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { struct stv0299_state* state = fe->demodulator_priv; @@ -647,7 +647,6 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &stv0299_ops, sizeof(struct dvb_frontend_ops)); state->initialised = 0; state->tuner_frequency = 0; state->symbol_rate = 0; @@ -664,7 +663,7 @@ struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, if (id != 0xa1 && id != 0x80) goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &stv0299_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -695,6 +694,7 @@ static struct dvb_frontend_ops stv0299_ops = { .init = stv0299_init, .sleep = stv0299_sleep, + .i2c_gate_ctrl = stv0299_i2c_gate_ctrl, .set_frontend = stv0299_set_frontend, .get_frontend = stv0299_get_frontend, @@ -721,9 +721,8 @@ MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); MODULE_DESCRIPTION("ST STV0299 DVB Demodulator driver"); MODULE_AUTHOR("Ralph Metzler, Holger Waechtler, Peter Schildmann, Felix Domke, " - "Andreas Oberritter, Andrew de Quincey, Kenneth Aafløy"); + "Andreas Oberritter, Andrew de Quincey, Kenneth Aafly"); MODULE_LICENSE("GPL"); -EXPORT_SYMBOL(stv0299_enable_plli2c); EXPORT_SYMBOL(stv0299_writereg); EXPORT_SYMBOL(stv0299_attach); diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h index 32c87b4c2f1..1504828e423 100644 --- a/drivers/media/dvb/frontends/stv0299.h +++ b/drivers/media/dvb/frontends/stv0299.h @@ -87,14 +87,9 @@ struct stv0299_config /* Set the symbol rate */ int (*set_symbol_rate)(struct dvb_frontend* fe, u32 srate, u32 ratio); - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend *fe, struct i2c_adapter *i2c); - int (*pll_set)(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params); }; extern int stv0299_writereg (struct dvb_frontend* fe, u8 reg, u8 data); -extern int stv0299_enable_plli2c (struct dvb_frontend* fe); extern struct dvb_frontend* stv0299_attach(const struct stv0299_config* config, struct i2c_adapter* i2c); diff --git a/drivers/media/dvb/frontends/tda10021.c b/drivers/media/dvb/frontends/tda10021.c index 21255cac979..e83ff2104c9 100644 --- a/drivers/media/dvb/frontends/tda10021.c +++ b/drivers/media/dvb/frontends/tda10021.c @@ -36,7 +36,6 @@ struct tda10021_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; /* configuration settings */ const struct tda10021_config* config; struct dvb_frontend frontend; @@ -90,6 +89,14 @@ static int tda10021_writereg (struct tda10021_state* state, u8 reg, u8 data) return (ret != 1) ? -EREMOTEIO : 0; } +int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data) +{ + struct tda10021_state* state = fe->demodulator_priv; + + return tda10021_writereg(state, reg, data); +} +EXPORT_SYMBOL(tda10021_write_byte); + static u8 tda10021_readreg (struct tda10021_state* state, u8 reg) { u8 b0 [] = { reg }; @@ -225,13 +232,6 @@ static int tda10021_init (struct dvb_frontend *fe) //Activate PLL tda10021_writereg(state, 0x2a, tda10021_inittab[0x2a] & 0xef); - - if (state->config->pll_init) { - lock_tuner(state); - state->config->pll_init(fe); - unlock_tuner(state); - } - return 0; } @@ -259,9 +259,10 @@ static int tda10021_set_parameters (struct dvb_frontend *fe, //printk("tda10021: set frequency to %d qam=%d symrate=%d\n", p->frequency,qam,p->u.qam.symbol_rate); - lock_tuner(state); - state->config->pll_set(fe, p); - unlock_tuner(state); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } tda10021_set_symbolrate (state, p->u.qam.symbol_rate); tda10021_writereg (state, 0x34, state->pwm); @@ -376,6 +377,18 @@ static int tda10021_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_pa return 0; } +static int tda10021_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct tda10021_state* state = fe->demodulator_priv; + + if (enable) { + lock_tuner(state); + } else { + unlock_tuner(state); + } + return 0; +} + static int tda10021_sleep(struct dvb_frontend* fe) { struct tda10021_state* state = fe->demodulator_priv; @@ -407,7 +420,6 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &tda10021_ops, sizeof(struct dvb_frontend_ops)); state->pwm = pwm; state->reg0 = tda10021_inittab[0]; @@ -415,7 +427,7 @@ struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, if ((tda10021_readreg(state, 0x1a) & 0xf0) != 0x70) goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &tda10021_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -448,6 +460,7 @@ static struct dvb_frontend_ops tda10021_ops = { .init = tda10021_init, .sleep = tda10021_sleep, + .i2c_gate_ctrl = tda10021_i2c_gate_ctrl, .set_frontend = tda10021_set_parameters, .get_frontend = tda10021_get_frontend, diff --git a/drivers/media/dvb/frontends/tda10021.h b/drivers/media/dvb/frontends/tda10021.h index 53be939e8c5..b1df4259bee 100644 --- a/drivers/media/dvb/frontends/tda10021.h +++ b/drivers/media/dvb/frontends/tda10021.h @@ -30,13 +30,11 @@ struct tda10021_config { /* the demodulator's i2c address */ u8 demod_address; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; extern struct dvb_frontend* tda10021_attach(const struct tda10021_config* config, struct i2c_adapter* i2c, u8 pwm); +extern int tda10021_write_byte(struct dvb_frontend* fe, int reg, int data); + #endif // TDA10021_H diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c index b83dafa4e12..59a2ed614fc 100644 --- a/drivers/media/dvb/frontends/tda1004x.c +++ b/drivers/media/dvb/frontends/tda1004x.c @@ -47,7 +47,6 @@ enum tda1004x_demod { struct tda1004x_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; const struct tda1004x_config* config; struct dvb_frontend frontend; @@ -600,13 +599,6 @@ static int tda10045_init(struct dvb_frontend* fe) tda1004x_write_mask(state, TDA1004X_CONFADC1, 0x10, 0); // wake up the ADC - // Init the PLL - if (state->config->pll_init) { - tda1004x_enable_tuner_i2c(state); - state->config->pll_init(fe); - tda1004x_disable_tuner_i2c(state); - } - // tda setup tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer tda1004x_write_mask(state, TDA1004X_AUTO, 8, 0); // select HP stream @@ -635,16 +627,6 @@ static int tda10046_init(struct dvb_frontend* fe) return -EIO; } - // Init the tuner PLL - if (state->config->pll_init) { - tda1004x_enable_tuner_i2c(state); - if (state->config->pll_init(fe)) { - printk(KERN_ERR "tda1004x: pll init failed\n"); - return -EIO; - } - tda1004x_disable_tuner_i2c(state); - } - // tda setup tda1004x_write_mask(state, TDA1004X_CONFC4, 0x20, 0); // disable DSP watchdog timer tda1004x_write_byteI(state, TDA1004X_AUTO, 0x87); // 100 ppm crystal, select HP stream @@ -712,12 +694,10 @@ static int tda1004x_set_fe(struct dvb_frontend* fe, } // set frequency - tda1004x_enable_tuner_i2c(state); - if (state->config->pll_set(fe, fe_params)) { - printk(KERN_ERR "tda1004x: pll set failed\n"); - return -EIO; + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, fe_params); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); } - tda1004x_disable_tuner_i2c(state); // Hardcoded to use auto as much as possible on the TDA10045 as it // is very unreliable if AUTO mode is _not_ used. @@ -1183,16 +1163,6 @@ static int tda1004x_sleep(struct dvb_frontend* fe) break; case TDA1004X_DEMOD_TDA10046: - if (state->config->pll_sleep != NULL) { - tda1004x_enable_tuner_i2c(state); - state->config->pll_sleep(fe); - if (state->config->if_freq != TDA10046_FREQ_052) { - /* special hack for Philips EUROPA Based boards: - * keep the I2c bridge open for tuner access in analog mode - */ - tda1004x_disable_tuner_i2c(state); - } - } /* set outputs to tristate */ tda1004x_write_byteI(state, TDA10046H_CONF_TRISTATE1, 0xff); tda1004x_write_mask(state, TDA1004X_CONFC4, 1, 1); @@ -1202,6 +1172,17 @@ static int tda1004x_sleep(struct dvb_frontend* fe) return 0; } +static int tda1004x_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct tda1004x_state* state = fe->demodulator_priv; + + if (enable) { + return tda1004x_enable_tuner_i2c(state); + } else { + return tda1004x_disable_tuner_i2c(state); + } +} + static int tda1004x_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings* fesettings) { fesettings->min_delay_ms = 800; @@ -1235,6 +1216,7 @@ static struct dvb_frontend_ops tda10045_ops = { .init = tda10045_init, .sleep = tda1004x_sleep, + .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl, .set_frontend = tda1004x_set_fe, .get_frontend = tda1004x_get_fe, @@ -1260,7 +1242,6 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); state->demod_type = TDA1004X_DEMOD_TDA10045; /* check if the demod is there */ @@ -1270,7 +1251,7 @@ struct dvb_frontend* tda10045_attach(const struct tda1004x_config* config, } /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &tda10045_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; } @@ -1293,6 +1274,7 @@ static struct dvb_frontend_ops tda10046_ops = { .init = tda10046_init, .sleep = tda1004x_sleep, + .i2c_gate_ctrl = tda1004x_i2c_gate_ctrl, .set_frontend = tda1004x_set_fe, .get_frontend = tda1004x_get_fe, @@ -1318,7 +1300,6 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); state->demod_type = TDA1004X_DEMOD_TDA10046; /* check if the demod is there */ @@ -1328,7 +1309,7 @@ struct dvb_frontend* tda10046_attach(const struct tda1004x_config* config, } /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &tda10046_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; } diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h index cc0c4af6406..b877b23ed73 100644 --- a/drivers/media/dvb/frontends/tda1004x.h +++ b/drivers/media/dvb/frontends/tda1004x.h @@ -66,11 +66,6 @@ struct tda1004x_config /* AGC configuration */ enum tda10046_agc agc_config; - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - void (*pll_sleep)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); - /* request firmware for device */ /* set this to NULL if the card has a firmware EEPROM */ int (*request_firmware)(struct dvb_frontend* fe, const struct firmware **fw, char* name); diff --git a/drivers/media/dvb/frontends/tda8083.c b/drivers/media/dvb/frontends/tda8083.c index 91baa9cedd7..3aa45ebbac3 100644 --- a/drivers/media/dvb/frontends/tda8083.c +++ b/drivers/media/dvb/frontends/tda8083.c @@ -37,7 +37,6 @@ struct tda8083_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; /* configuration settings */ const struct tda8083_config* config; struct dvb_frontend frontend; @@ -293,7 +292,11 @@ static int tda8083_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par { struct tda8083_state* state = fe->demodulator_priv; - state->config->pll_set(fe, p); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + tda8083_set_inversion (state, p->inversion); tda8083_set_fec (state, p->u.qpsk.fec_inner); tda8083_set_symbolrate (state, p->u.qpsk.symbol_rate); @@ -334,8 +337,6 @@ static int tda8083_init(struct dvb_frontend* fe) for (i=0; i<44; i++) tda8083_writereg (state, i, tda8083_init_tab[i]); - if (state->config->pll_init) state->config->pll_init(fe); - tda8083_writereg (state, 0x00, 0x3c); tda8083_writereg (state, 0x00, 0x04); @@ -395,13 +396,12 @@ struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &tda8083_ops, sizeof(struct dvb_frontend_ops)); /* check if the demod is there */ if ((tda8083_readreg(state, 0x00)) != 0x05) goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &tda8083_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; diff --git a/drivers/media/dvb/frontends/tda8083.h b/drivers/media/dvb/frontends/tda8083.h index 466663307bf..e7a48f61ea2 100644 --- a/drivers/media/dvb/frontends/tda8083.h +++ b/drivers/media/dvb/frontends/tda8083.h @@ -33,10 +33,6 @@ struct tda8083_config { /* the demodulator's i2c address */ u8 demod_address; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; extern struct dvb_frontend* tda8083_attach(const struct tda8083_config* config, diff --git a/drivers/media/dvb/frontends/ves1820.c b/drivers/media/dvb/frontends/ves1820.c index ad8647a3c85..6bffe85c161 100644 --- a/drivers/media/dvb/frontends/ves1820.c +++ b/drivers/media/dvb/frontends/ves1820.c @@ -35,7 +35,6 @@ struct ves1820_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; /* configuration settings */ const struct ves1820_config* config; struct dvb_frontend frontend; @@ -204,9 +203,6 @@ static int ves1820_init(struct dvb_frontend* fe) ves1820_writereg(state, 0x34, state->pwm); - if (state->config->pll_init) - state->config->pll_init(fe); - return 0; } @@ -223,7 +219,11 @@ static int ves1820_set_parameters(struct dvb_frontend* fe, struct dvb_frontend_p if (real_qam < 0 || real_qam > 4) return -EINVAL; - state->config->pll_set(fe, p); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + ves1820_set_symbolrate(state, p->u.qam.symbol_rate); ves1820_writereg(state, 0x34, state->pwm); @@ -380,7 +380,6 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, goto error; /* setup the state */ - memcpy(&state->ops, &ves1820_ops, sizeof(struct dvb_frontend_ops)); state->reg0 = ves1820_inittab[0]; state->config = config; state->i2c = i2c; @@ -393,12 +392,12 @@ struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, if (verbose) printk("ves1820: pwm=0x%02x\n", state->pwm); - state->ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */ - state->ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */ - /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &ves1820_ops, sizeof(struct dvb_frontend_ops)); + state->frontend.ops.info.symbol_rate_min = (state->config->xin / 2) / 64; /* SACLK/64 == (XIN/2)/64 */ + state->frontend.ops.info.symbol_rate_max = (state->config->xin / 2) / 4; /* SACLK/4 */ state->frontend.demodulator_priv = state; + return &state->frontend; error: diff --git a/drivers/media/dvb/frontends/ves1820.h b/drivers/media/dvb/frontends/ves1820.h index 355f130b1be..520f09522fb 100644 --- a/drivers/media/dvb/frontends/ves1820.h +++ b/drivers/media/dvb/frontends/ves1820.h @@ -39,10 +39,6 @@ struct ves1820_config /* SELAGC control */ u8 selagc:1; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; extern struct dvb_frontend* ves1820_attach(const struct ves1820_config* config, diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c index 821df8e839d..54d7b07571b 100644 --- a/drivers/media/dvb/frontends/ves1x93.c +++ b/drivers/media/dvb/frontends/ves1x93.c @@ -36,7 +36,6 @@ struct ves1x93_state { struct i2c_adapter* i2c; - struct dvb_frontend_ops ops; /* configuration settings */ const struct ves1x93_config* config; struct dvb_frontend frontend; @@ -278,12 +277,6 @@ static int ves1x93_init (struct dvb_frontend* fe) } } - if (state->config->pll_init) { - ves1x93_writereg(state, 0x00, 0x11); - state->config->pll_init(fe); - ves1x93_writereg(state, 0x00, 0x01); - } - return 0; } @@ -395,9 +388,10 @@ static int ves1x93_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par { struct ves1x93_state* state = fe->demodulator_priv; - ves1x93_writereg(state, 0x00, 0x11); - state->config->pll_set(fe, p); - ves1x93_writereg(state, 0x00, 0x01); + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, p); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } ves1x93_set_inversion (state, p->inversion); ves1x93_set_fec (state, p->u.qpsk.fec_inner); ves1x93_set_symbolrate (state, p->u.qpsk.symbol_rate); @@ -442,6 +436,17 @@ static void ves1x93_release(struct dvb_frontend* fe) kfree(state); } +static int ves1x93_i2c_gate_ctrl(struct dvb_frontend* fe, int enable) +{ + struct ves1x93_state* state = fe->demodulator_priv; + + if (enable) { + return ves1x93_writereg(state, 0x00, 0x11); + } else { + return ves1x93_writereg(state, 0x00, 0x01); + } +} + static struct dvb_frontend_ops ves1x93_ops; struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, @@ -457,7 +462,6 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, /* setup the state */ state->config = config; state->i2c = i2c; - memcpy(&state->ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops)); state->inversion = INVERSION_OFF; /* check if the demod is there + identify it */ @@ -492,7 +496,7 @@ struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, } /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &ves1x93_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; @@ -523,6 +527,7 @@ static struct dvb_frontend_ops ves1x93_ops = { .init = ves1x93_init, .sleep = ves1x93_sleep, + .i2c_gate_ctrl = ves1x93_i2c_gate_ctrl, .set_frontend = ves1x93_set_frontend, .get_frontend = ves1x93_get_frontend, diff --git a/drivers/media/dvb/frontends/ves1x93.h b/drivers/media/dvb/frontends/ves1x93.h index 1627e37c57a..ba88ae0855c 100644 --- a/drivers/media/dvb/frontends/ves1x93.h +++ b/drivers/media/dvb/frontends/ves1x93.h @@ -38,10 +38,6 @@ struct ves1x93_config /* should PWM be inverted? */ u8 invert_pwm:1; - - /* PLL maintenance */ - int (*pll_init)(struct dvb_frontend* fe); - int (*pll_set)(struct dvb_frontend* fe, struct dvb_frontend_parameters* params); }; extern struct dvb_frontend* ves1x93_attach(const struct ves1x93_config* config, diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c index d7d9f59d76d..2b95e8b6cd3 100644 --- a/drivers/media/dvb/frontends/zl10353.c +++ b/drivers/media/dvb/frontends/zl10353.c @@ -34,7 +34,6 @@ struct zl10353_state { struct i2c_adapter *i2c; struct dvb_frontend frontend; - struct dvb_frontend_ops ops; struct zl10353_config config; }; @@ -126,6 +125,7 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) { struct zl10353_state *state = fe->demodulator_priv; + u8 pllbuf[6] = { 0x67 }; /* These settings set "auto-everything" and start the FSM. */ @@ -142,7 +142,30 @@ static int zl10353_set_parameters(struct dvb_frontend *fe, zl10353_single_write(fe, 0x66, 0xE9); zl10353_single_write(fe, 0x62, 0x0A); - state->config.pll_set(fe, param, pllbuf + 1); + // if there is no attached secondary tuner, we call set_params to program + // a potential tuner attached somewhere else + if (state->config.no_tuner) { + if (fe->ops.tuner_ops.set_params) { + fe->ops.tuner_ops.set_params(fe, param); + if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0); + } + } + + // if pllbuf is defined, retrieve the settings + if (fe->ops.tuner_ops.calc_regs) { + fe->ops.tuner_ops.calc_regs(fe, param, pllbuf+1, 5); + pllbuf[1] <<= 1; + } else { + // fake pllbuf settings + pllbuf[1] = 0x61 << 1; + pllbuf[2] = 0; + pllbuf[3] = 0; + pllbuf[3] = 0; + pllbuf[4] = 0; + } + + // there is no call to _just_ start decoding, so we send the pllbuf anyway + // even if there isn't a PLL attached to the secondary bus zl10353_write(fe, pllbuf, sizeof(pllbuf)); zl10353_single_write(fe, 0x70, 0x01); @@ -254,14 +277,13 @@ struct dvb_frontend *zl10353_attach(const struct zl10353_config *config, /* setup the state */ state->i2c = i2c; memcpy(&state->config, config, sizeof(struct zl10353_config)); - memcpy(&state->ops, &zl10353_ops, sizeof(struct dvb_frontend_ops)); /* check if the demod is there */ if (zl10353_read_register(state, CHIP_ID) != ID_ZL10353) goto error; /* create dvb_frontend */ - state->frontend.ops = &state->ops; + memcpy(&state->frontend.ops, &zl10353_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; diff --git a/drivers/media/dvb/frontends/zl10353.h b/drivers/media/dvb/frontends/zl10353.h index 5cc4ae718d8..9770cb840cf 100644 --- a/drivers/media/dvb/frontends/zl10353.h +++ b/drivers/media/dvb/frontends/zl10353.h @@ -29,10 +29,8 @@ struct zl10353_config /* demodulator's I2C address */ u8 demod_address; - /* function which configures the PLL buffer (for secondary I2C - * connected tuner) or tunes the PLL (for direct connected tuner) */ - int (*pll_set)(struct dvb_frontend *fe, - struct dvb_frontend_parameters *params, u8 *pllbuf); + /* set if no pll is connected to the secondary i2c bus */ + int no_tuner; }; extern struct dvb_frontend* zl10353_attach(const struct zl10353_config *config, diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c index 1c5316e209e..acabea0793b 100644 --- a/drivers/media/dvb/pluto2/pluto2.c +++ b/drivers/media/dvb/pluto2/pluto2.c @@ -424,8 +424,8 @@ static inline u32 divide(u32 numerator, u32 denominator) } /* LG Innotek TDTE-E001P (Infineon TUA6034) */ -static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe, - struct dvb_frontend_parameters *p) +static int lg_tdtpe001p_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) { struct pluto *pluto = frontend_to_pluto(fe); struct i2c_msg msg; @@ -473,6 +473,8 @@ static int lg_tdtpe001p_pll_set(struct dvb_frontend *fe, msg.buf = buf; msg.len = sizeof(buf); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); ret = i2c_transfer(&pluto->i2c_adap, &msg, 1); if (ret < 0) return ret; @@ -497,8 +499,6 @@ static struct tda1004x_config pluto2_fe_config __devinitdata = { .xtal_freq = TDA10046_XTAL_16M, .agc_config = TDA10046_AGC_DEFAULT, .if_freq = TDA10046_FREQ_3617, - .pll_set = lg_tdtpe001p_pll_set, - .pll_sleep = NULL, .request_firmware = pluto2_request_firmware, }; @@ -511,11 +511,12 @@ static int __devinit frontend_init(struct pluto *pluto) dev_err(&pluto->pdev->dev, "could not attach frontend\n"); return -ENODEV; } + pluto->fe->ops.tuner_ops.set_params = lg_tdtpe001p_tuner_set_params; ret = dvb_register_frontend(&pluto->dvb_adapter, pluto->fe); if (ret < 0) { - if (pluto->fe->ops->release) - pluto->fe->ops->release(pluto->fe); + if (pluto->fe->ops.release) + pluto->fe->ops.release(pluto->fe); return ret; } @@ -647,7 +648,7 @@ static int __devinit pluto2_probe(struct pci_dev *pdev, goto err_pluto_hw_exit; /* dvb */ - ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE); + ret = dvb_register_adapter(&pluto->dvb_adapter, DRIVER_NAME, THIS_MODULE, &pdev->dev); if (ret < 0) goto err_i2c_bit_del_bus; diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig index b5ac7dfde52..987881fa988 100644 --- a/drivers/media/dvb/ttpci/Kconfig +++ b/drivers/media/dvb/ttpci/Kconfig @@ -10,6 +10,7 @@ config DVB_AV7110 select DVB_SP8870 select DVB_STV0297 select DVB_L64781 + select DVB_LNBP21 help Support for SAA7146 and AV7110 based DVB cards as produced by Fujitsu-Siemens, Technotrend, Hauppauge and others. @@ -67,6 +68,7 @@ config DVB_BUDGET select DVB_TDA8083 select DVB_TDA10021 select DVB_S5H1420 + select DVB_LNBP21 help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard @@ -84,6 +86,7 @@ config DVB_BUDGET_CI select DVB_STV0297 select DVB_STV0299 select DVB_TDA1004X + select DVB_LNBP21 help Support for simple SAA7146 based DVB cards (so called Budget- or Nova-PCI cards) without onboard diff --git a/drivers/media/dvb/ttpci/Makefile b/drivers/media/dvb/ttpci/Makefile index a690730ac39..aa85ecdc6c8 100644 --- a/drivers/media/dvb/ttpci/Makefile +++ b/drivers/media/dvb/ttpci/Makefile @@ -15,9 +15,9 @@ EXTRA_CFLAGS = -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/ hostprogs-y := fdump -ifdef CONFIG_DVB_AV7110_FIRMWARE -$(obj)/av7110.o: $(obj)/fdump $(obj)/av7110_firm.h +ifeq ($(CONFIG_DVB_AV7110_FIRMWARE),y) +$(obj)/av7110.o: $(obj)/av7110_firm.h -$(obj)/av7110_firm.h: +$(obj)/av7110_firm.h: $(obj)/fdump $(obj)/fdump $(CONFIG_DVB_AV7110_FIRMWARE_FILE) dvb_ttpci_fw $@ endif diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c index d028245c8ee..7a5c99c200e 100644 --- a/drivers/media/dvb/ttpci/av7110.c +++ b/drivers/media/dvb/ttpci/av7110.c @@ -152,13 +152,9 @@ static void init_av7110_av(struct av7110 *av7110) /* remaining inits according to card and frontend type */ av7110->analog_tuner_flags = 0; av7110->current_input = 0; - if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) { - printk("dvb-ttpci: MSP3415 audio DAC @ card %d\n", - av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_MSP34x5; + if (dev->pci->subsystem_vendor == 0x13c2 && dev->pci->subsystem_device == 0x000a) av7110_fw_cmd(av7110, COMTYPE_AUDIODAC, ADSwitch, 1, 0); // SPDIF on - } - else if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { + if (i2c_writereg(av7110, 0x20, 0x00, 0x00) == 1) { printk ("dvb-ttpci: Crystal audio DAC @ card %d detected\n", av7110->dvb_adapter.num); av7110->adac_type = DVB_ADAC_CRYSTAL; @@ -1552,7 +1548,7 @@ static int get_firmware(struct av7110* av7110) #endif -static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) { struct av7110* av7110 = (struct av7110*) fe->dvb->priv; u8 pwr = 0; @@ -1575,6 +1571,8 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param // NOTE: since we're using a prescaler of 2, we set the // divisor frequency to 62.5kHz and divide by 125 above + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO; return 0; @@ -1584,10 +1582,9 @@ static struct ves1x93_config alps_bsrv2_config = { .demod_address = 0x08, .xin = 90100000UL, .invert_pwm = 0, - .pll_set = alps_bsrv2_pll_set, }; -static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) { struct av7110* av7110 = fe->dvb->priv; u32 div; @@ -1601,6 +1598,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param data[2] = 0x85 | ((div >> 10) & 0x60); data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) return -EIO; return 0; @@ -1611,14 +1610,12 @@ static struct ves1820_config alps_tdbe2_config = { .xin = 57840000UL, .invert = 1, .selagc = VES1820_SELAGC_SIGNAMPERR, - .pll_set = alps_tdbe2_pll_set, }; -static int grundig_29504_451_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) +static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) { struct av7110* av7110 = fe->dvb->priv; u32 div; @@ -1631,6 +1628,8 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, data[2] = 0x8e; data[3] = 0x00; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) return -EIO; return 0; @@ -1638,13 +1637,11 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, static struct tda8083_config grundig_29504_451_config = { .demod_address = 0x68, - .pll_set = grundig_29504_451_pll_set, }; -static int philips_cd1516_pll_set(struct dvb_frontend* fe, - struct dvb_frontend_parameters* params) +static int philips_cd1516_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) { struct av7110* av7110 = fe->dvb->priv; u32 div; @@ -1659,6 +1656,8 @@ static int philips_cd1516_pll_set(struct dvb_frontend* fe, data[2] = 0x8e; data[3] = (f < 174000000 ? 0xa1 : f < 470000000 ? 0x92 : 0x34); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) return -EIO; return 0; @@ -1669,12 +1668,11 @@ static struct ves1820_config philips_cd1516_config = { .xin = 57840000UL, .invert = 1, .selagc = VES1820_SELAGC_SIGNAMPERR, - .pll_set = philips_cd1516_pll_set, }; -static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdlb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) { struct av7110* av7110 = fe->dvb->priv; u32 div, pwr; @@ -1693,6 +1691,8 @@ static int alps_tdlb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param data[2] = 0x85; data[3] = pwr << 6; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) return -EIO; return 0; @@ -1708,7 +1708,6 @@ static int alps_tdlb7_request_firmware(struct dvb_frontend* fe, const struct fir static struct sp8870_config alps_tdlb7_config = { .demod_address = 0x71, - .pll_set = alps_tdlb7_pll_set, .request_firmware = alps_tdlb7_request_firmware, }; @@ -1806,7 +1805,7 @@ static u8 nexusca_stv0297_inittab[] = { 0xff, 0xff, }; -static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int nexusca_stv0297_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) { struct av7110* av7110 = fe->dvb->priv; u32 div; @@ -1832,7 +1831,8 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ else return -EINVAL; - stv0297_enable_plli2c(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&av7110->i2c_adap, &msg, 1) != 1) { printk("nexusca: pll transfer failed!\n"); return -EIO; @@ -1840,8 +1840,8 @@ static int nexusca_stv0297_pll_set(struct dvb_frontend* fe, struct dvb_frontend_ // wait for PLL lock for(i = 0; i < 20; i++) { - - stv0297_enable_plli2c(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&av7110->i2c_adap, &readmsg, 1) == 1) if (data[0] & 0x40) break; msleep(10); @@ -1855,12 +1855,12 @@ static struct stv0297_config nexusca_stv0297_config = { .demod_address = 0x1C, .inittab = nexusca_stv0297_inittab, .invert = 1, - .pll_set = nexusca_stv0297_pll_set, + .stop_during_read = 1, }; -static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters *params) { struct av7110* av7110 = (struct av7110*) fe->dvb->priv; u32 div; @@ -1887,13 +1887,14 @@ static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_fronten data[2] = ((div >> 10) & 0x60) | cfg; data[3] = (cpump << 6) | band_select; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer (&av7110->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } static struct l64781_config grundig_29504_401_config = { .demod_address = 0x55, - .pll_set = grundig_29504_401_pll_set, }; @@ -2079,6 +2080,9 @@ static int frontend_init(struct av7110 *av7110) case 0x0000: // Fujitsu/Siemens DVB-Cable (ves1820/Philips CD1516(??)) av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; + } break; } @@ -2091,9 +2095,10 @@ static int frontend_init(struct av7110 *av7110) // try the ALPS BSRV2 first of all av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap); if (av7110->fe) { - av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops->set_tone = av7110_set_tone; + av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; av7110->recover = dvb_s_recover; break; } @@ -2101,9 +2106,12 @@ static int frontend_init(struct av7110 *av7110) // try the ALPS BSRU6 now av7110->fe = stv0299_attach(&alps_bsru6_config, &av7110->i2c_adap); if (av7110->fe) { - av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops->set_tone = av7110_set_tone; + av7110->fe->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + av7110->fe->tuner_priv = &av7110->i2c_adap; + + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; av7110->recover = dvb_s_recover; break; } @@ -2111,9 +2119,10 @@ static int frontend_init(struct av7110 *av7110) // Try the grundig 29504-451 av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap); if (av7110->fe) { - av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops->set_tone = av7110_set_tone; + av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; av7110->recover = dvb_s_recover; break; } @@ -2124,11 +2133,17 @@ static int frontend_init(struct av7110 *av7110) /* Siemens DVB-C (full-length card) VES1820/Philips CD1516 */ av7110->fe = ves1820_attach(&philips_cd1516_config, &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = philips_cd1516_tuner_set_params; + } break; case 0x0003: /* Hauppauge DVB-C 2.1 VES1820/ALPS TDBE2 */ av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + } break; } break; @@ -2137,20 +2152,27 @@ static int frontend_init(struct av7110 *av7110) // ALPS TDLB7 av7110->fe = sp8870_attach(&alps_tdlb7_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdlb7_tuner_set_params; + } break; case 0x0002: // Hauppauge/TT DVB-C premium rev2.X av7110->fe = ves1820_attach(&alps_tdbe2_config, &av7110->i2c_adap, read_pwm(av7110)); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + } break; case 0x0004: // Galaxis DVB-S rev1.3 /* ALPS BSRV2 */ av7110->fe = ves1x93_attach(&alps_bsrv2_config, &av7110->i2c_adap); if (av7110->fe) { - av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops->set_tone = av7110_set_tone; + av7110->fe->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; av7110->recover = dvb_s_recover; } break; @@ -2159,9 +2181,10 @@ static int frontend_init(struct av7110 *av7110) /* Grundig 29504-451 */ av7110->fe = tda8083_attach(&grundig_29504_451_config, &av7110->i2c_adap); if (av7110->fe) { - av7110->fe->ops->diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; - av7110->fe->ops->diseqc_send_burst = av7110_diseqc_send_burst; - av7110->fe->ops->set_tone = av7110_set_tone; + av7110->fe->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + av7110->fe->ops.diseqc_send_master_cmd = av7110_diseqc_send_master_cmd; + av7110->fe->ops.diseqc_send_burst = av7110_diseqc_send_burst; + av7110->fe->ops.set_tone = av7110_set_tone; av7110->recover = dvb_s_recover; } break; @@ -2169,12 +2192,17 @@ static int frontend_init(struct av7110 *av7110) case 0x0008: // Hauppauge/TT DVB-T av7110->fe = l64781_attach(&grundig_29504_401_config, &av7110->i2c_adap); + if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + } break; case 0x000A: // Hauppauge/TT Nexus-CA rev1.X av7110->fe = stv0297_attach(&nexusca_stv0297_config, &av7110->i2c_adap); if (av7110->fe) { + av7110->fe->ops.tuner_ops.set_params = nexusca_stv0297_tuner_set_params; + /* set TDA9819 into DVB mode */ saa7146_setgpio(av7110->dev, 1, SAA7146_GPIO_OUTLO); // TDA9198 pin9(STD) saa7146_setgpio(av7110->dev, 3, SAA7146_GPIO_OUTLO); // TDA9198 pin30(VIF) @@ -2189,13 +2217,16 @@ static int frontend_init(struct av7110 *av7110) /* ALPS BSBE1 */ av7110->fe = stv0299_attach(&alps_bsbe1_config, &av7110->i2c_adap); if (av7110->fe) { - if (lnbp21_init(av7110->fe, &av7110->i2c_adap, 0, 0)) { + av7110->fe->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; + av7110->fe->tuner_priv = &av7110->i2c_adap; + + if (lnbp21_attach(av7110->fe, &av7110->i2c_adap, 0, 0)) { printk("dvb-ttpci: LNBP21 not found!\n"); - if (av7110->fe->ops->release) - av7110->fe->ops->release(av7110->fe); + if (av7110->fe->ops.release) + av7110->fe->ops.release(av7110->fe); av7110->fe = NULL; } else { - av7110->fe->ops->dishnetwork_send_legacy_command = NULL; + av7110->fe->ops.dishnetwork_send_legacy_command = NULL; av7110->recover = dvb_s_recover; } } @@ -2212,21 +2243,21 @@ static int frontend_init(struct av7110 *av7110) av7110->dev->pci->subsystem_vendor, av7110->dev->pci->subsystem_device); } else { - FE_FUNC_OVERRIDE(av7110->fe->ops->init, av7110->fe_init, av7110_fe_init); - FE_FUNC_OVERRIDE(av7110->fe->ops->read_status, av7110->fe_read_status, av7110_fe_read_status); - FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload); - FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd); - FE_FUNC_OVERRIDE(av7110->fe->ops->diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst); - FE_FUNC_OVERRIDE(av7110->fe->ops->set_tone, av7110->fe_set_tone, av7110_fe_set_tone); - FE_FUNC_OVERRIDE(av7110->fe->ops->set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;) - FE_FUNC_OVERRIDE(av7110->fe->ops->dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command); - FE_FUNC_OVERRIDE(av7110->fe->ops->set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend); + FE_FUNC_OVERRIDE(av7110->fe->ops.init, av7110->fe_init, av7110_fe_init); + FE_FUNC_OVERRIDE(av7110->fe->ops.read_status, av7110->fe_read_status, av7110_fe_read_status); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_reset_overload, av7110->fe_diseqc_reset_overload, av7110_fe_diseqc_reset_overload); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_master_cmd, av7110->fe_diseqc_send_master_cmd, av7110_fe_diseqc_send_master_cmd); + FE_FUNC_OVERRIDE(av7110->fe->ops.diseqc_send_burst, av7110->fe_diseqc_send_burst, av7110_fe_diseqc_send_burst); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_tone, av7110->fe_set_tone, av7110_fe_set_tone); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_voltage, av7110->fe_set_voltage, av7110_fe_set_voltage;) + FE_FUNC_OVERRIDE(av7110->fe->ops.dishnetwork_send_legacy_command, av7110->fe_dishnetwork_send_legacy_command, av7110_fe_dishnetwork_send_legacy_command); + FE_FUNC_OVERRIDE(av7110->fe->ops.set_frontend, av7110->fe_set_frontend, av7110_fe_set_frontend); ret = dvb_register_frontend(&av7110->dvb_adapter, av7110->fe); if (ret < 0) { printk("av7110: Frontend registration failed!\n"); - if (av7110->fe->ops->release) - av7110->fe->ops->release(av7110->fe); + if (av7110->fe->ops.release) + av7110->fe->ops.release(av7110->fe); av7110->fe = NULL; } } @@ -2413,7 +2444,7 @@ static int __devinit av7110_attach(struct saa7146_dev* dev, goto err_kfree_0; ret = dvb_register_adapter(&av7110->dvb_adapter, av7110->card_name, - THIS_MODULE); + THIS_MODULE, &dev->pci->dev); if (ret < 0) goto err_put_firmware_1; diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c index 2eff09f638d..0f3a044aeb1 100644 --- a/drivers/media/dvb/ttpci/av7110_av.c +++ b/drivers/media/dvb/ttpci/av7110_av.c @@ -318,7 +318,17 @@ int av7110_set_volume(struct av7110 *av7110, int volleft, int volright) msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ msp_writereg(av7110, MSP_WR_DSP, 0x0006, val); /* headphonesr */ return 0; + + case DVB_ADAC_MSP34x5: + vol = (volleft > volright) ? volleft : volright; + val = (vol * 0x73 / 255) << 8; + if (vol > 0) + balance = ((volright - volleft) * 127) / vol; + msp_writereg(av7110, MSP_WR_DSP, 0x0001, balance << 8); + msp_writereg(av7110, MSP_WR_DSP, 0x0000, val); /* loudspeaker */ + return 0; } + return 0; } @@ -1267,23 +1277,32 @@ static int dvb_audio_ioctl(struct inode *inode, struct file *file, switch(av7110->audiostate.channel_select) { case AUDIO_STEREO: ret = audcom(av7110, AUDIO_CMD_STEREO); - if (!ret) + if (!ret) { if (av7110->adac_type == DVB_ADAC_CRYSTAL) i2c_writereg(av7110, 0x20, 0x02, 0x49); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0220); + } break; case AUDIO_MONO_LEFT: ret = audcom(av7110, AUDIO_CMD_MONO_L); - if (!ret) + if (!ret) { if (av7110->adac_type == DVB_ADAC_CRYSTAL) i2c_writereg(av7110, 0x20, 0x02, 0x4a); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0200); + } break; case AUDIO_MONO_RIGHT: ret = audcom(av7110, AUDIO_CMD_MONO_R); - if (!ret) + if (!ret) { if (av7110->adac_type == DVB_ADAC_CRYSTAL) i2c_writereg(av7110, 0x20, 0x02, 0x45); + else if (av7110->adac_type == DVB_ADAC_MSP34x5) + msp_writereg(av7110, MSP_WR_DSP, 0x0008, 0x0210); + } break; default: diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c index 603a22e4bfe..64055461559 100644 --- a/drivers/media/dvb/ttpci/av7110_v4l.c +++ b/drivers/media/dvb/ttpci/av7110_v4l.c @@ -42,7 +42,18 @@ int msp_writereg(struct av7110 *av7110, u8 dev, u16 reg, u16 val) { u8 msg[5] = { dev, reg >> 8, reg & 0xff, val >> 8 , val & 0xff }; - struct i2c_msg msgs = { .flags = 0, .addr = 0x40, .len = 5, .buf = msg }; + struct i2c_msg msgs = { .flags = 0, .len = 5, .buf = msg }; + + switch (av7110->adac_type) { + case DVB_ADAC_MSP34x0: + msgs.addr = 0x40; + break; + case DVB_ADAC_MSP34x5: + msgs.addr = 0x42; + break; + default: + return 0; + } if (i2c_transfer(&av7110->i2c_adap, &msgs, 1) != 1) { dprintk(1, "dvb-ttpci: failed @ card %d, %u = %u\n", @@ -57,10 +68,23 @@ static int msp_readreg(struct av7110 *av7110, u8 dev, u16 reg, u16 *val) u8 msg1[3] = { dev, reg >> 8, reg & 0xff }; u8 msg2[2]; struct i2c_msg msgs[2] = { - { .flags = 0, .addr = 0x40, .len = 3, .buf = msg1 }, - { .flags = I2C_M_RD, .addr = 0x40, .len = 2, .buf = msg2 } + { .flags = 0 , .len = 3, .buf = msg1 }, + { .flags = I2C_M_RD, .len = 2, .buf = msg2 } }; + switch (av7110->adac_type) { + case DVB_ADAC_MSP34x0: + msgs[0].addr = 0x40; + msgs[1].addr = 0x40; + break; + case DVB_ADAC_MSP34x5: + msgs[0].addr = 0x42; + msgs[1].addr = 0x42; + break; + default: + return 0; + } + if (i2c_transfer(&av7110->i2c_adap, &msgs[0], 2) != 2) { dprintk(1, "dvb-ttpci: failed @ card %d, %u\n", av7110->dvb_adapter.num, reg); @@ -678,17 +702,23 @@ int av7110_init_analog_module(struct av7110 *av7110) { u16 version1, version2; - if (i2c_writereg(av7110, 0x80, 0x0, 0x80) != 1 - || i2c_writereg(av7110, 0x80, 0x0, 0) != 1) + if (i2c_writereg(av7110, 0x80, 0x0, 0x80) == 1 && + i2c_writereg(av7110, 0x80, 0x0, 0) == 1) { + printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_MSP34x0; + } else if (i2c_writereg(av7110, 0x84, 0x0, 0x80) == 1 && + i2c_writereg(av7110, 0x84, 0x0, 0) == 1) { + printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3415\n", + av7110->dvb_adapter.num); + av7110->adac_type = DVB_ADAC_MSP34x5; + } else return -ENODEV; - printk("dvb-ttpci: DVB-C analog module @ card %d detected, initializing MSP3400\n", - av7110->dvb_adapter.num); - av7110->adac_type = DVB_ADAC_MSP34x0; msleep(100); // the probing above resets the msp... msp_readreg(av7110, MSP_RD_DSP, 0x001e, &version1); msp_readreg(av7110, MSP_RD_DSP, 0x001f, &version2); - dprintk(1, "dvb-ttpci: @ card %d MSP3400 version 0x%04x 0x%04x\n", + dprintk(1, "dvb-ttpci: @ card %d MSP34xx version 0x%04x 0x%04x\n", av7110->dvb_adapter.num, version1, version2); msp_writereg(av7110, MSP_WR_DSP, 0x0013, 0x0c00); msp_writereg(av7110, MSP_WR_DSP, 0x0000, 0x7f00); // loudspeaker + headphone @@ -697,7 +727,7 @@ int av7110_init_analog_module(struct av7110 *av7110) msp_writereg(av7110, MSP_WR_DSP, 0x0004, 0x7f00); // loudspeaker volume msp_writereg(av7110, MSP_WR_DSP, 0x000a, 0x0220); // SCART 1 source msp_writereg(av7110, MSP_WR_DSP, 0x0007, 0x7f00); // SCART 1 volume - msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x4800); // prescale SCART + msp_writereg(av7110, MSP_WR_DSP, 0x000d, 0x1900); // prescale SCART if (i2c_writereg(av7110, 0x48, 0x01, 0x00)!=1) { INFO(("saa7113 not accessible.\n")); diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c index 8a7cd7d505c..6163cb03b8f 100644 --- a/drivers/media/dvb/ttpci/budget-av.c +++ b/drivers/media/dvb/ttpci/budget-av.c @@ -50,6 +50,12 @@ #define DEBICICAM 0x02420000 +#define SLOTSTATUS_NONE 1 +#define SLOTSTATUS_PRESENT 2 +#define SLOTSTATUS_RESET 4 +#define SLOTSTATUS_READY 8 +#define SLOTSTATUS_OCCUPIED (SLOTSTATUS_PRESENT|SLOTSTATUS_RESET|SLOTSTATUS_READY) + struct budget_av { struct budget budget; struct video_device *vd; @@ -58,8 +64,15 @@ struct budget_av { struct tasklet_struct ciintf_irq_tasklet; int slot_status; struct dvb_ca_en50221 ca; + u8 reinitialise_demod:1; + u8 tda10021_poclkp:1; + u8 tda10021_ts_enabled; + int (*tda10021_set_frontend)(struct dvb_frontend *fe, struct dvb_frontend_parameters *p); }; +static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot); + + /* GPIO Connections: * 0 - Vcc/Reset (Reset is controlled by capacitor). Resets the frontend *AS WELL*! * 1 - CI memory select 0=>IO memory, 1=>Attribute Memory @@ -129,9 +142,10 @@ static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int ad udelay(1); result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 0xfff, 1, 0, 1); - - if (result == -ETIMEDOUT) - budget_av->slot_status = 0; + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected 1\n"); + } return result; } @@ -147,9 +161,10 @@ static int ciintf_write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int a udelay(1); result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 0xfff, 1, value, 0, 1); - - if (result == -ETIMEDOUT) - budget_av->slot_status = 0; + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected 2\n"); + } return result; } @@ -165,9 +180,11 @@ static int ciintf_read_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addre udelay(1); result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, address & 3, 1, 0, 0); - - if (result == -ETIMEDOUT) - budget_av->slot_status = 0; + if ((result == -ETIMEDOUT) || ((result == 0xff) && ((address & 3) < 2))) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected 3\n"); + return -ETIMEDOUT; + } return result; } @@ -183,9 +200,10 @@ static int ciintf_write_cam_control(struct dvb_ca_en50221 *ca, int slot, u8 addr udelay(1); result = ttpci_budget_debiwrite(&budget_av->budget, DEBICICAM, address & 3, 1, value, 0, 0); - - if (result == -ETIMEDOUT) - budget_av->slot_status = 0; + if (result == -ETIMEDOUT) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected 5\n"); + } return result; } @@ -193,12 +211,12 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; - int timeout = 50; // 5 seconds (4.4.6 Ready) if (slot != 0) return -EINVAL; dprintk(1, "ciintf_slot_reset\n"); + budget_av->slot_status = SLOTSTATUS_RESET; saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ @@ -208,20 +226,17 @@ static int ciintf_slot_reset(struct dvb_ca_en50221 *ca, int slot) msleep(20); /* 20 ms Vcc settling time */ saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTLO); /* enable card */ + ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); + msleep(20); - /* This should have been based on pin 16 READY of the pcmcia port, - * but AFAICS it is not routed to the saa7146 */ - while (--timeout > 0 && ciintf_read_attribute_mem(ca, slot, 0) != 0x1d) - msleep(100); - - /* reinitialise the frontend */ - dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); + /* reinitialise the frontend if necessary */ + if (budget_av->reinitialise_demod) + dvb_frontend_reinitialise(budget_av->budget.dvb_frontend); - if (timeout <= 0) - { - printk(KERN_ERR "budget-av: cam reset failed (timeout).\n"); - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - return -ETIMEDOUT; + /* set tda10021 back to original clock configuration on reset */ + if (budget_av->tda10021_poclkp) { + tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0); + budget_av->tda10021_ts_enabled = 0; } return 0; @@ -238,7 +253,13 @@ static int ciintf_slot_shutdown(struct dvb_ca_en50221 *ca, int slot) dprintk(1, "ciintf_slot_shutdown\n"); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTB); - budget_av->slot_status = 0; + budget_av->slot_status = SLOTSTATUS_NONE; + + /* set tda10021 back to original clock configuration when cam removed */ + if (budget_av->tda10021_poclkp) { + tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0); + budget_av->tda10021_ts_enabled = 0; + } return 0; } @@ -253,6 +274,13 @@ static int ciintf_slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) dprintk(1, "ciintf_slot_ts_enable: %d\n", budget_av->slot_status); ttpci_budget_set_video_port(saa, BUDGET_VIDEO_PORTA); + + /* tda10021 seems to need a different TS clock config when data is routed to the CAM */ + if (budget_av->tda10021_poclkp) { + tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1); + budget_av->tda10021_ts_enabled = 1; + } + return 0; } @@ -260,50 +288,61 @@ static int ciintf_poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open { struct budget_av *budget_av = (struct budget_av *) ca->data; struct saa7146_dev *saa = budget_av->budget.dev; - int cam_present = 0; + int result; if (slot != 0) return -EINVAL; - if (!budget_av->slot_status) - { - // first of all test the card detect line + /* test the card detect line - needs to be done carefully + * since it never goes high for some CAMs on this interface (e.g. topuptv) */ + if (budget_av->slot_status == SLOTSTATUS_NONE) { saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT); udelay(1); - if (saa7146_read(saa, PSR) & MASK_06) - { - cam_present = 1; + if (saa7146_read(saa, PSR) & MASK_06) { + if (budget_av->slot_status == SLOTSTATUS_NONE) { + budget_av->slot_status = SLOTSTATUS_PRESENT; + printk(KERN_INFO "budget-av: cam inserted A\n"); + } } saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTLO); + } - // that is unreliable however, so try and read from IO memory - if (!cam_present) - { - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) != -ETIMEDOUT) - { - cam_present = 1; + /* We also try and read from IO memory to work round the above detection bug. If + * there is no CAM, we will get a timeout. Only done if there is no cam + * present, since this test actually breaks some cams :( + * + * if the CI interface is not open, we also do the above test since we + * don't care if the cam has problems - we'll be resetting it on open() anyway */ + if ((budget_av->slot_status == SLOTSTATUS_NONE) || (!open)) { + saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); + result = ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1); + if ((result >= 0) && (budget_av->slot_status == SLOTSTATUS_NONE)) { + budget_av->slot_status = SLOTSTATUS_PRESENT; + printk(KERN_INFO "budget-av: cam inserted B\n"); + } else if (result < 0) { + if (budget_av->slot_status != SLOTSTATUS_NONE) { + ciintf_slot_shutdown(ca, slot); + printk(KERN_INFO "budget-av: cam ejected 5\n"); + return 0; } } + } - // did we find something? - if (cam_present) { - printk(KERN_INFO "budget-av: cam inserted\n"); - budget_av->slot_status = 1; - } - } else if (!open) { - saa7146_setgpio(budget_av->budget.dev, 1, SAA7146_GPIO_OUTLO); - if (ttpci_budget_debiread(&budget_av->budget, DEBICICAM, 0, 1, 0, 1) == -ETIMEDOUT) - { - printk(KERN_INFO "budget-av: cam ejected\n"); - saa7146_setgpio(saa, 2, SAA7146_GPIO_OUTHI); /* disable card */ - budget_av->slot_status = 0; + /* read from attribute memory in reset/ready state to know when the CAM is ready */ + if (budget_av->slot_status == SLOTSTATUS_RESET) { + result = ciintf_read_attribute_mem(ca, slot, 0); + if (result == 0x1d) { + budget_av->slot_status = SLOTSTATUS_READY; } } - if (budget_av->slot_status == 1) - return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; - + /* work out correct return code */ + if (budget_av->slot_status != SLOTSTATUS_NONE) { + if (budget_av->slot_status & SLOTSTATUS_READY) { + return DVB_CA_EN50221_POLL_CAM_PRESENT | DVB_CA_EN50221_POLL_CAM_READY; + } + return DVB_CA_EN50221_POLL_CAM_PRESENT; + } return 0; } @@ -333,6 +372,8 @@ static int ciintf_init(struct budget_av *budget_av) budget_av->ca.slot_ts_enable = ciintf_slot_ts_enable; budget_av->ca.poll_slot_status = ciintf_poll_slot_status; budget_av->ca.data = budget_av; + budget_av->budget.ci_present = 1; + budget_av->slot_status = SLOTSTATUS_NONE; if ((result = dvb_ca_en50221_init(&budget_av->budget.dvb_adapter, &budget_av->ca, 0, 1)) != 0) { @@ -341,7 +382,6 @@ static int ciintf_init(struct budget_av *budget_av) } printk(KERN_INFO "budget-av: ci interface initialised.\n"); - budget_av->budget.ci_present = 1; return 0; error: @@ -472,12 +512,12 @@ static int philips_su1278_ty_ci_set_symbol_rate(struct dvb_frontend *fe, u32 sra return 0; } -static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct dvb_frontend_parameters *params) +static int philips_su1278_ty_ci_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) { u32 div; u8 buf[4]; + struct budget *budget = (struct budget *) fe->dvb->priv; struct i2c_msg msg = {.addr = 0x61,.flags = 0,.buf = buf,.len = sizeof(buf) }; if ((params->frequency < 950000) || (params->frequency > 2150000)) @@ -501,7 +541,9 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe, else if (params->frequency < 2150000) buf[3] |= 0xC0; - if (i2c_transfer(i2c, &msg, 1) != 1) + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } @@ -509,9 +551,8 @@ static int philips_su1278_ty_ci_pll_set(struct dvb_frontend *fe, #define MIN2(a,b) ((a) < (b) ? (a) : (b)) #define MIN3(a,b,c) MIN2(MIN2(a,b),c) -static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct dvb_frontend_parameters *params) +static int philips_su1278sh2_tua6100_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) { u8 reg0 [2] = { 0x00, 0x00 }; u8 reg1 [4] = { 0x01, 0x00, 0x00, 0x00 }; @@ -521,6 +562,7 @@ static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe, int R, A, N, P, M; struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = NULL,.len = 0 }; int freq = params->frequency; + struct budget *budget = (struct budget *) fe->dvb->priv; first_ZF = (freq) / 1000; @@ -620,21 +662,25 @@ static int philips_su1278sh2_tua6100_pll_set(struct dvb_frontend *fe, reg0[1] |= 0x03; /* already enabled - do not reenable i2c repeater or TX fails */ + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); msg.buf = reg0; msg.len = sizeof(reg0); - if (i2c_transfer(i2c, &msg, 1) != 1) + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) return -EIO; - stv0299_enable_plli2c(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); msg.buf = reg1; msg.len = sizeof(reg1); - if (i2c_transfer(i2c, &msg, 1) != 1) + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) return -EIO; - stv0299_enable_plli2c(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); msg.buf = reg2; msg.len = sizeof(reg2); - if (i2c_transfer(i2c, &msg, 1) != 1) + if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) return -EIO; return 0; @@ -692,7 +738,6 @@ static struct stv0299_config typhoon_config = { .volt13_op0_op1 = STV0299_VOLT13_OP0, .min_delay_ms = 100, .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, - .pll_set = philips_su1278_ty_ci_pll_set, }; @@ -706,7 +751,6 @@ static struct stv0299_config cinergy_1200s_config = { .volt13_op0_op1 = STV0299_VOLT13_OP0, .min_delay_ms = 100, .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, - .pll_set = philips_su1278_ty_ci_pll_set, }; static struct stv0299_config cinergy_1200s_1894_0010_config = { @@ -719,10 +763,9 @@ static struct stv0299_config cinergy_1200s_1894_0010_config = { .volt13_op0_op1 = STV0299_VOLT13_OP0, .min_delay_ms = 100, .set_symbol_rate = philips_su1278_ty_ci_set_symbol_rate, - .pll_set = philips_su1278sh2_tua6100_pll_set, }; -static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_cu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct budget *budget = (struct budget *) fe->dvb->priv; u8 buf[4]; @@ -738,6 +781,8 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p buf[3] = (params->frequency < 150000000 ? 0x01 : params->frequency < 445000000 ? 0x02 : 0x04); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&budget->i2c_adap, &msg, 1) != 1) return -EIO; return 0; @@ -745,19 +790,20 @@ static int philips_cu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p static struct tda10021_config philips_cu1216_config = { .demod_address = 0x0c, - .pll_set = philips_cu1216_pll_set, }; -static int philips_tu1216_pll_init(struct dvb_frontend *fe) +static int philips_tu1216_tuner_init(struct dvb_frontend *fe) { struct budget *budget = (struct budget *) fe->dvb->priv; static u8 tu1216_init[] = { 0x0b, 0xf5, 0x85, 0xab }; struct i2c_msg tuner_msg = {.addr = 0x60,.flags = 0,.buf = tu1216_init,.len = sizeof(tu1216_init) }; // setup PLL configuration + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) return -EIO; msleep(1); @@ -765,7 +811,7 @@ static int philips_tu1216_pll_init(struct dvb_frontend *fe) return 0; } -static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tu1216_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct budget *budget = (struct budget *) fe->dvb->priv; u8 tuner_buf[4]; @@ -839,6 +885,8 @@ static int philips_tu1216_pll_set(struct dvb_frontend *fe, struct dvb_frontend_p tuner_buf[2] = 0xca; tuner_buf[3] = (cp << 5) | (filter << 3) | band; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) return -EIO; @@ -862,9 +910,6 @@ static struct tda1004x_config philips_tu1216_config = { .xtal_freq = TDA10046_XTAL_4M, .agc_config = TDA10046_AGC_DEFAULT, .if_freq = TDA10046_FREQ_3617, - .pll_init = philips_tu1216_pll_init, - .pll_set = philips_tu1216_pll_set, - .pll_sleep = NULL, .request_firmware = philips_tu1216_request_firmware, }; @@ -911,13 +956,13 @@ static u8 philips_sd1878_inittab[] = { 0xff, 0xff }; -static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct dvb_frontend_parameters *params) +static int philips_sd1878_tda8261_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) { u8 buf[4]; int rc; struct i2c_msg tuner_msg = {.addr=0x60,.flags=0,.buf=buf,.len=sizeof(buf)}; + struct budget *budget = (struct budget *) fe->dvb->priv; if((params->frequency < 950000) || (params->frequency > 2150000)) return -EINVAL; @@ -926,7 +971,9 @@ static int philips_sd1878_tda8261_pll_set(struct dvb_frontend *fe, params->frequency, 0); if(rc < 0) return rc; - if(i2c_transfer(i2c, &tuner_msg, 1) != 1) + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if(i2c_transfer(&budget->i2c_adap, &tuner_msg, 1) != 1) return -EIO; return 0; @@ -969,7 +1016,7 @@ static int philips_sd1878_ci_set_symbol_rate(struct dvb_frontend *fe, static struct stv0299_config philips_sd1878_config = { .demod_address = 0x68, - .inittab = philips_sd1878_inittab, + .inittab = philips_sd1878_inittab, .mclk = 88000000UL, .invert = 0, .skip_reinit = 0, @@ -977,7 +1024,6 @@ static struct stv0299_config philips_sd1878_config = { .volt13_op0_op1 = STV0299_VOLT13_OP0, .min_delay_ms = 100, .set_symbol_rate = philips_sd1878_ci_set_symbol_rate, - .pll_set = philips_sd1878_tda8261_pll_set, }; static u8 read_pwm(struct budget_av *budget_av) @@ -1003,6 +1049,7 @@ static u8 read_pwm(struct budget_av *budget_av) #define SUBID_DVBS_TV_STAR 0x0014 #define SUBID_DVBS_TV_STAR_CI 0x0016 +#define SUBID_DVBS_EASYWATCH_1 0x001a #define SUBID_DVBS_EASYWATCH 0x001e #define SUBID_DVBC_KNC1 0x0020 #define SUBID_DVBC_KNC1_PLUS 0x0021 @@ -1012,17 +1059,36 @@ static u8 read_pwm(struct budget_av *budget_av) #define SUBID_DVBT_KNC1 0x0030 #define SUBID_DVBT_CINERGY1200 0x1157 + +static int tda10021_set_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p) +{ + struct budget_av* budget_av = fe->dvb->priv; + int result; + + result = budget_av->tda10021_set_frontend(fe, p); + if (budget_av->tda10021_ts_enabled) { + tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa1); + } else { + tda10021_write_byte(budget_av->budget.dvb_frontend, 0x12, 0xa0); + } + + return result; +} + static void frontend_init(struct budget_av *budget_av) { struct saa7146_dev * saa = budget_av->budget.dev; struct dvb_frontend * fe = NULL; + /* Enable / PowerON Frontend */ + saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); + + /* additional setup necessary for the PLUS cards */ switch (saa->pci->subsystem_device) { case SUBID_DVBS_KNC1_PLUS: case SUBID_DVBC_KNC1_PLUS: case SUBID_DVBT_KNC1_PLUS: - // Enable / PowerON Frontend - saa7146_setgpio(saa, 0, SAA7146_GPIO_OUTLO); saa7146_setgpio(saa, 3, SAA7146_GPIO_OUTHI); break; } @@ -1030,12 +1096,19 @@ static void frontend_init(struct budget_av *budget_av) switch (saa->pci->subsystem_device) { case SUBID_DVBS_KNC1: + case SUBID_DVBS_EASYWATCH_1: if (saa->pci->subsystem_vendor == 0x1894) { fe = stv0299_attach(&cinergy_1200s_1894_0010_config, &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_su1278sh2_tua6100_tuner_set_params; + } } else { fe = stv0299_attach(&typhoon_config, &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; + } } break; @@ -1045,41 +1118,53 @@ static void frontend_init(struct budget_av *budget_av) case SUBID_DVBS_EASYWATCH: fe = stv0299_attach(&philips_sd1878_config, &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_sd1878_tda8261_tuner_set_params; + } break; case SUBID_DVBS_KNC1_PLUS: case SUBID_DVBS_TYPHOON: fe = stv0299_attach(&typhoon_config, &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; + } break; case SUBID_DVBS_CINERGY1200: fe = stv0299_attach(&cinergy_1200s_config, &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.set_params = philips_su1278_ty_ci_tuner_set_params; + } break; case SUBID_DVBC_KNC1: case SUBID_DVBC_KNC1_PLUS: + case SUBID_DVBC_CINERGY1200: + budget_av->reinitialise_demod = 1; fe = tda10021_attach(&philips_cu1216_config, &budget_av->budget.i2c_adap, read_pwm(budget_av)); + if (fe) { + budget_av->tda10021_poclkp = 1; + budget_av->tda10021_set_frontend = fe->ops.set_frontend; + fe->ops.set_frontend = tda10021_set_frontend; + fe->ops.tuner_ops.set_params = philips_cu1216_tuner_set_params; + } break; case SUBID_DVBT_KNC1: case SUBID_DVBT_KNC1_PLUS: - fe = tda10046_attach(&philips_tu1216_config, - &budget_av->budget.i2c_adap); - break; - - case SUBID_DVBC_CINERGY1200: - fe = tda10021_attach(&philips_cu1216_config, - &budget_av->budget.i2c_adap, - read_pwm(budget_av)); - break; - case SUBID_DVBT_CINERGY1200: + budget_av->reinitialise_demod = 1; fe = tda10046_attach(&philips_tu1216_config, &budget_av->budget.i2c_adap); + if (fe) { + fe->ops.tuner_ops.init = philips_tu1216_tuner_init; + fe->ops.tuner_ops.set_params = philips_tu1216_tuner_set_params; + } break; } @@ -1098,8 +1183,8 @@ static void frontend_init(struct budget_av *budget_av) if (dvb_register_frontend(&budget_av->budget.dvb_adapter, budget_av->budget.dvb_frontend)) { printk(KERN_ERR "budget-av: Frontend registration failed!\n"); - if (budget_av->budget.dvb_frontend->ops->release) - budget_av->budget.dvb_frontend->ops->release(budget_av->budget.dvb_frontend); + if (budget_av->budget.dvb_frontend->ops.release) + budget_av->budget.dvb_frontend->ops.release(budget_av->budget.dvb_frontend); budget_av->budget.dvb_frontend = NULL; } } @@ -1293,6 +1378,7 @@ MAKE_BUDGET_INFO(knc1c, "KNC1 DVB-C", BUDGET_KNC1C); MAKE_BUDGET_INFO(knc1t, "KNC1 DVB-T", BUDGET_KNC1T); MAKE_BUDGET_INFO(kncxs, "KNC TV STAR DVB-S", BUDGET_TVSTAR); MAKE_BUDGET_INFO(satewpls, "Satelco EasyWatch DVB-S light", BUDGET_TVSTAR); +MAKE_BUDGET_INFO(satewpls1, "Satelco EasyWatch DVB-S light", BUDGET_KNC1S); MAKE_BUDGET_INFO(knc1sp, "KNC1 DVB-S Plus", BUDGET_KNC1SP); MAKE_BUDGET_INFO(knc1cp, "KNC1 DVB-C Plus", BUDGET_KNC1CP); MAKE_BUDGET_INFO(knc1tp, "KNC1 DVB-T Plus", BUDGET_KNC1TP); @@ -1309,6 +1395,7 @@ static struct pci_device_id pci_tbl[] = { MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0014), MAKE_EXTENSION_PCI(kncxs, 0x1894, 0x0016), MAKE_EXTENSION_PCI(satewpls, 0x1894, 0x001e), + MAKE_EXTENSION_PCI(satewpls1, 0x1894, 0x001a), MAKE_EXTENSION_PCI(knc1c, 0x1894, 0x0020), MAKE_EXTENSION_PCI(knc1cp, 0x1894, 0x0021), MAKE_EXTENSION_PCI(knc1t, 0x1894, 0x0030), diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c index e64a609cf4f..4b966eea383 100644 --- a/drivers/media/dvb/ttpci/budget-ci.c +++ b/drivers/media/dvb/ttpci/budget-ci.c @@ -620,10 +620,10 @@ static int philips_su1278_tt_set_symbol_rate(struct dvb_frontend *fe, u32 srate, return 0; } -static int philips_su1278_tt_pll_set(struct dvb_frontend *fe, - struct i2c_adapter *i2c, - struct dvb_frontend_parameters *params) +static int philips_su1278_tt_tuner_set_params(struct dvb_frontend *fe, + struct dvb_frontend_parameters *params) { + struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u32 div; u8 buf[4]; struct i2c_msg msg = {.addr = 0x60,.flags = 0,.buf = buf,.len = sizeof(buf) }; @@ -649,7 +649,9 @@ static int philips_su1278_tt_pll_set(struct dvb_frontend *fe, else if (params->frequency < 2150000) buf[3] |= 0xC0; - if (i2c_transfer(i2c, &msg, 1) != 1) + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&budget_ci->budget.i2c_adap, &msg, 1) != 1) return -EIO; return 0; } @@ -665,12 +667,11 @@ static struct stv0299_config philips_su1278_tt_config = { .volt13_op0_op1 = STV0299_VOLT13_OP1, .min_delay_ms = 50, .set_symbol_rate = philips_su1278_tt_set_symbol_rate, - .pll_set = philips_su1278_tt_pll_set, }; -static int philips_tdm1316l_pll_init(struct dvb_frontend *fe) +static int philips_tdm1316l_tuner_init(struct dvb_frontend *fe) { struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; @@ -679,6 +680,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe) sizeof(td1316_init) }; // setup PLL configuration + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) return -EIO; msleep(1); @@ -687,14 +690,18 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend *fe) tuner_msg.addr = 0x65; tuner_msg.buf = disable_mc44BC374c; tuner_msg.len = sizeof(disable_mc44BC374c); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) { + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1); } return 0; } -static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u8 tuner_buf[4]; @@ -770,6 +777,8 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend tuner_buf[2] = 0xca; tuner_buf[3] = (cp << 5) | (filter << 3) | band; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) return -EIO; @@ -793,13 +802,10 @@ static struct tda1004x_config philips_tdm1316l_config = { .xtal_freq = TDA10046_XTAL_4M, .agc_config = TDA10046_AGC_DEFAULT, .if_freq = TDA10046_FREQ_3617, - .pll_init = philips_tdm1316l_pll_init, - .pll_set = philips_tdm1316l_pll_set, - .pll_sleep = NULL, .request_firmware = philips_tdm1316l_request_firmware, }; -static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct budget_ci *budget_ci = (struct budget_ci *) fe->dvb->priv; u8 tuner_buf[5]; @@ -857,13 +863,15 @@ static int dvbc_philips_tdm1316l_pll_set(struct dvb_frontend *fe, struct dvb_fro tuner_buf[3] = (cp << 5) | (filter << 3) | band; tuner_buf[4] = 0x80; - stv0297_enable_plli2c(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) return -EIO; msleep(50); - stv0297_enable_plli2c(fe); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&budget_ci->budget.i2c_adap, &tuner_msg, 1) != 1) return -EIO; @@ -969,7 +977,7 @@ static struct stv0297_config dvbc_philips_tdm1316l_config = { .demod_address = 0x1c, .inittab = dvbc_philips_tdm1316l_inittab, .invert = 0, - .pll_set = dvbc_philips_tdm1316l_pll_set, + .stop_during_read = 1, }; @@ -982,6 +990,8 @@ static void frontend_init(struct budget_ci *budget_ci) budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget_ci->budget.i2c_adap); if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; break; } break; @@ -990,6 +1000,7 @@ static void frontend_init(struct budget_ci *budget_ci) budget_ci->budget.dvb_frontend = stv0299_attach(&philips_su1278_tt_config, &budget_ci->budget.i2c_adap); if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_su1278_tt_tuner_set_params; break; } break; @@ -999,6 +1010,7 @@ static void frontend_init(struct budget_ci *budget_ci) budget_ci->budget.dvb_frontend = stv0297_attach(&dvbc_philips_tdm1316l_config, &budget_ci->budget.i2c_adap); if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; break; } break; @@ -1008,6 +1020,8 @@ static void frontend_init(struct budget_ci *budget_ci) budget_ci->budget.dvb_frontend = tda10045_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap); if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; break; } break; @@ -1017,6 +1031,8 @@ static void frontend_init(struct budget_ci *budget_ci) budget_ci->budget.dvb_frontend = tda10046_attach(&philips_tdm1316l_config, &budget_ci->budget.i2c_adap); if (budget_ci->budget.dvb_frontend) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.init = philips_tdm1316l_tuner_init; + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; break; } break; @@ -1024,11 +1040,14 @@ static void frontend_init(struct budget_ci *budget_ci) case 0x1017: // TT S-1500 PCI budget_ci->budget.dvb_frontend = stv0299_attach(&alps_bsbe1_config, &budget_ci->budget.i2c_adap); if (budget_ci->budget.dvb_frontend) { - budget_ci->budget.dvb_frontend->ops->dishnetwork_send_legacy_command = NULL; - if (lnbp21_init(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) { + budget_ci->budget.dvb_frontend->ops.tuner_ops.set_params = alps_bsbe1_tuner_set_params; + budget_ci->budget.dvb_frontend->tuner_priv = &budget_ci->budget.i2c_adap; + + budget_ci->budget.dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; + if (lnbp21_attach(budget_ci->budget.dvb_frontend, &budget_ci->budget.i2c_adap, LNBP21_LLC, 0)) { printk("%s: No LNBP21 found!\n", __FUNCTION__); - if (budget_ci->budget.dvb_frontend->ops->release) - budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend); + if (budget_ci->budget.dvb_frontend->ops.release) + budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend); budget_ci->budget.dvb_frontend = NULL; } } @@ -1046,8 +1065,8 @@ static void frontend_init(struct budget_ci *budget_ci) if (dvb_register_frontend (&budget_ci->budget.dvb_adapter, budget_ci->budget.dvb_frontend)) { printk("budget-ci: Frontend registration failed!\n"); - if (budget_ci->budget.dvb_frontend->ops->release) - budget_ci->budget.dvb_frontend->ops->release(budget_ci->budget.dvb_frontend); + if (budget_ci->budget.dvb_frontend->ops.release) + budget_ci->budget.dvb_frontend->ops.release(budget_ci->budget.dvb_frontend); budget_ci->budget.dvb_frontend = NULL; } } diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c index ea2066d461f..e4cf7775e07 100644 --- a/drivers/media/dvb/ttpci/budget-core.c +++ b/drivers/media/dvb/ttpci/budget-core.c @@ -400,7 +400,9 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev, budget->dev->name, budget->buffer_width, budget->buffer_height); printk("%s: dma buffer size %u\n", budget->dev->name, budget->buffer_size); - dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner); + if ((ret = dvb_register_adapter(&budget->dvb_adapter, budget->card->name, owner, &budget->dev->pci->dev)) < 0) { + return ret; + } /* set dd1 stream a & b */ saa7146_write(dev, DD1_STREAM_B, 0x00000000); diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c index 1b3aaac5e76..ee60ce90a40 100644 --- a/drivers/media/dvb/ttpci/budget-patch.c +++ b/drivers/media/dvb/ttpci/budget-patch.c @@ -258,7 +258,7 @@ static int budget_patch_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_c return 0; } -static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; u8 pwr = 0; @@ -281,7 +281,10 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param // NOTE: since we're using a prescaler of 2, we set the // divisor frequency to 62.5kHz and divide by 125 above - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) + return -EIO; return 0; } @@ -289,10 +292,9 @@ static struct ves1x93_config alps_bsrv2_config = { .demod_address = 0x08, .xin = 90100000UL, .invert_pwm = 0, - .pll_set = alps_bsrv2_pll_set, }; -static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct budget_patch* budget = (struct budget_patch*) fe->dvb->priv; u32 div; @@ -305,13 +307,15 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_fronten data[2] = 0x8e; data[3] = 0x00; - if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) + return -EIO; return 0; } static struct tda8083_config grundig_29504_451_config = { .demod_address = 0x68, - .pll_set = grundig_29504_451_pll_set, }; static void frontend_init(struct budget_patch* budget) @@ -323,27 +327,32 @@ static void frontend_init(struct budget_patch* budget) // try the ALPS BSRV2 first of all budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap); if (budget->dvb_frontend) { - budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; - budget->dvb_frontend->ops->diseqc_send_burst = budget_patch_diseqc_send_burst; - budget->dvb_frontend->ops->set_tone = budget_patch_set_tone; + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_patch_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_patch_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_patch_set_tone; break; } // try the ALPS BSRU6 now budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap); if (budget->dvb_frontend) { - budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops->set_tone = budget_set_tone; + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; break; } // Try the grundig 29504-451 budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap); if (budget->dvb_frontend) { - budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops->set_tone = budget_set_tone; + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; break; } break; @@ -358,8 +367,8 @@ static void frontend_init(struct budget_patch* budget) } else { if (dvb_register_frontend(&budget->dvb_adapter, budget->dvb_frontend)) { printk("budget-av: Frontend registration failed!\n"); - if (budget->dvb_frontend->ops->release) - budget->dvb_frontend->ops->release(budget->dvb_frontend); + if (budget->dvb_frontend->ops.release) + budget->dvb_frontend->ops.release(budget->dvb_frontend); budget->dvb_frontend = NULL; } } diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c index c23c02d9564..35761f13c12 100644 --- a/drivers/media/dvb/ttpci/budget.c +++ b/drivers/media/dvb/ttpci/budget.c @@ -186,7 +186,7 @@ static int budget_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t m return 0; } -static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_bsrv2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct budget* budget = (struct budget*) fe->dvb->priv; u8 pwr = 0; @@ -209,6 +209,8 @@ static int alps_bsrv2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param // NOTE: since we're using a prescaler of 2, we set the // divisor frequency to 62.5kHz and divide by 125 above + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } @@ -218,10 +220,9 @@ static struct ves1x93_config alps_bsrv2_config = .demod_address = 0x08, .xin = 90100000UL, .invert_pwm = 0, - .pll_set = alps_bsrv2_pll_set, }; -static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct budget* budget = (struct budget*) fe->dvb->priv; u32 div; @@ -235,6 +236,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param data[2] = 0x85 | ((div >> 10) & 0x60); data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } @@ -244,10 +247,9 @@ static struct ves1820_config alps_tdbe2_config = { .xin = 57840000UL, .invert = 1, .selagc = VES1820_SELAGC_SIGNAMPERR, - .pll_set = alps_tdbe2_pll_set, }; -static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int grundig_29504_401_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct budget* budget = (struct budget*) fe->dvb->priv; u32 div; @@ -274,16 +276,17 @@ static int grundig_29504_401_pll_set(struct dvb_frontend* fe, struct dvb_fronten data[2] = ((div >> 10) & 0x60) | cfg; data[3] = (cpump << 6) | band_select; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } static struct l64781_config grundig_29504_401_config = { .demod_address = 0x55, - .pll_set = grundig_29504_401_pll_set, }; -static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int grundig_29504_451_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct budget* budget = (struct budget*) fe->dvb->priv; u32 div; @@ -296,16 +299,17 @@ static int grundig_29504_451_pll_set(struct dvb_frontend* fe, struct dvb_fronten data[2] = 0x8e; data[3] = 0x00; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } static struct tda8083_config grundig_29504_451_config = { .demod_address = 0x68, - .pll_set = grundig_29504_451_pll_set, }; -static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params, u32* freqout) +static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct budget* budget = (struct budget*) fe->dvb->priv; u32 div; @@ -326,16 +330,16 @@ static int s5h1420_pll_set(struct dvb_frontend* fe, struct dvb_frontend_paramete else data[3] = 0xc0; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer (&budget->i2c_adap, &msg, 1) != 1) return -EIO; - *freqout = div * 1000; return 0; } static struct s5h1420_config s5h1420_config = { .demod_address = 0x53, .invert = 1, - .pll_set = s5h1420_pll_set, }; static u8 read_pwm(struct budget* budget) @@ -359,18 +363,21 @@ static void frontend_init(struct budget *budget) // try the ALPS BSRV2 first of all budget->dvb_frontend = ves1x93_attach(&alps_bsrv2_config, &budget->i2c_adap); if (budget->dvb_frontend) { - budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops->set_tone = budget_set_tone; + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsrv2_tuner_set_params; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; break; } // try the ALPS BSRU6 now budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap); if (budget->dvb_frontend) { - budget->dvb_frontend->ops->diseqc_send_master_cmd = budget_diseqc_send_master_cmd; - budget->dvb_frontend->ops->diseqc_send_burst = budget_diseqc_send_burst; - budget->dvb_frontend->ops->set_tone = budget_set_tone; + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + budget->dvb_frontend->ops.diseqc_send_master_cmd = budget_diseqc_send_master_cmd; + budget->dvb_frontend->ops.diseqc_send_burst = budget_diseqc_send_burst; + budget->dvb_frontend->ops.set_tone = budget_set_tone; break; } break; @@ -378,35 +385,45 @@ static void frontend_init(struct budget *budget) case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) budget->dvb_frontend = ves1820_attach(&alps_tdbe2_config, &budget->i2c_adap, read_pwm(budget)); - if (budget->dvb_frontend) break; + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + break; + } break; case 0x1005: // Hauppauge/TT Nova-T budget (L64781/Grundig 29504-401(tsa5060)) budget->dvb_frontend = l64781_attach(&grundig_29504_401_config, &budget->i2c_adap); - if (budget->dvb_frontend) break; + if (budget->dvb_frontend) { + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_401_tuner_set_params; + break; + } break; case 0x4f60: // Fujitsu Siemens Activy Budget-S PCI rev AL (stv0299/ALPS BSRU6(tsa5059)) budget->dvb_frontend = stv0299_attach(&alps_bsru6_config, &budget->i2c_adap); if (budget->dvb_frontend) { - budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL; + budget->dvb_frontend->ops.tuner_ops.set_params = alps_bsru6_tuner_set_params; + budget->dvb_frontend->tuner_priv = &budget->i2c_adap; + budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; + budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; } break; case 0x4f61: // Fujitsu Siemens Activy Budget-S PCI rev GR (tda8083/Grundig 29504-451(tsa5522)) budget->dvb_frontend = tda8083_attach(&grundig_29504_451_config, &budget->i2c_adap); if (budget->dvb_frontend) { - budget->dvb_frontend->ops->set_voltage = siemens_budget_set_voltage; - budget->dvb_frontend->ops->dishnetwork_send_legacy_command = NULL; + budget->dvb_frontend->ops.tuner_ops.set_params = grundig_29504_451_tuner_set_params; + budget->dvb_frontend->ops.set_voltage = siemens_budget_set_voltage; + budget->dvb_frontend->ops.dishnetwork_send_legacy_command = NULL; } break; case 0x1016: // Hauppauge/TT Nova-S SE (samsung s5h1420/????(tda8260)) budget->dvb_frontend = s5h1420_attach(&s5h1420_config, &budget->i2c_adap); if (budget->dvb_frontend) { - if (lnbp21_init(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) { + budget->dvb_frontend->ops.tuner_ops.set_params = s5h1420_tuner_set_params; + if (lnbp21_attach(budget->dvb_frontend, &budget->i2c_adap, 0, 0)) { printk("%s: No LNBP21 found!\n", __FUNCTION__); goto error_out; } @@ -428,8 +445,8 @@ static void frontend_init(struct budget *budget) error_out: printk("budget: Frontend registration failed!\n"); - if (budget->dvb_frontend->ops->release) - budget->dvb_frontend->ops->release(budget->dvb_frontend); + if (budget->dvb_frontend->ops.release) + budget->dvb_frontend->ops.release(budget->dvb_frontend); budget->dvb_frontend = NULL; return; } diff --git a/drivers/media/dvb/ttusb-budget/Kconfig b/drivers/media/dvb/ttusb-budget/Kconfig index 914587d52b5..92c7cdcf898 100644 --- a/drivers/media/dvb/ttusb-budget/Kconfig +++ b/drivers/media/dvb/ttusb-budget/Kconfig @@ -6,6 +6,8 @@ config DVB_TTUSB_BUDGET select DVB_VES1820 select DVB_TDA8083 select DVB_STV0299 + select DVB_STV0297 + select DVB_LNBP21 help Support for external USB adapters designed by Technotrend and produced by Hauppauge, shipped under the brand name 'Nova-USB'. diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c index 6ceae38125c..14559ef6153 100644 --- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c +++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c @@ -30,6 +30,8 @@ #include "tda1004x.h" #include "stv0299.h" #include "tda8083.h" +#include "stv0297.h" +#include "lnbp21.h" #include <linux/dvb/frontend.h> #include <linux/dvb/dmx.h> @@ -486,31 +488,6 @@ static int ttusb_send_diseqc(struct dvb_frontend* fe, } #endif -static int lnbp21_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage) -{ - struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; - int ret; - u8 data[1]; - struct i2c_msg msg = { .addr = 0x08, .flags = 0, .buf = data, .len = sizeof(data) }; - - switch(voltage) { - case SEC_VOLTAGE_OFF: - data[0] = 0x00; - break; - case SEC_VOLTAGE_13: - data[0] = 0x44; - break; - case SEC_VOLTAGE_18: - data[0] = 0x4c; - break; - default: - return -EINVAL; - }; - - ret = i2c_transfer(&ttusb->i2c_adap, &msg, 1); - return (ret != 1) ? -EIO : 0; -} - static int ttusb_update_lnb(struct ttusb *ttusb) { u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1, @@ -1048,7 +1025,7 @@ static u32 functionality(struct i2c_adapter *adapter) -static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdmb7_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 data[4]; @@ -1062,20 +1039,21 @@ static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param data[2] = ((div >> 10) & 0x60) | 0x85; data[3] = params->frequency < 592000000 ? 0x40 : 0x80; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO; return 0; } static 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) +static int philips_tdm1316l_tuner_init(struct dvb_frontend* fe) { struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab }; @@ -1083,6 +1061,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe) struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) }; // setup PLL configuration + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO; msleep(1); @@ -1090,6 +1070,8 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe) tuner_msg.addr = 0x65; tuner_msg.buf = disable_mc44BC374c; tuner_msg.len = sizeof(disable_mc44BC374c); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1); } @@ -1097,7 +1079,7 @@ static int philips_tdm1316l_pll_init(struct dvb_frontend* fe) return 0; } -static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int philips_tdm1316l_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 tuner_buf[4]; @@ -1157,6 +1139,8 @@ static int philips_tdm1316l_pll_set(struct dvb_frontend* fe, struct dvb_frontend tuner_buf[2] = 0xca; tuner_buf[3] = (cp << 5) | (filter << 3) | band; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO; @@ -1176,8 +1160,6 @@ static struct tda1004x_config philips_tdm1316l_config = { .demod_address = 0x8, .invert = 1, .invert_oclk = 0, - .pll_init = philips_tdm1316l_pll_init, - .pll_set = philips_tdm1316l_pll_set, .request_firmware = philips_tdm1316l_request_firmware, }; @@ -1299,7 +1281,7 @@ static int alps_stv0299_set_symbol_rate(struct dvb_frontend *fe, u32 srate, u32 return 0; } -static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct dvb_frontend_parameters *params) +static int philips_tsa5059_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 buf[4]; @@ -1322,7 +1304,9 @@ static int philips_tsa5059_pll_set(struct dvb_frontend *fe, struct i2c_adapter * if (ttusb->revision == TTUSB_REV_2_2) buf[3] |= 0x20; - if (i2c_transfer(i2c, &msg, 1) != 1) + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO; return 0; @@ -1338,10 +1322,9 @@ static struct stv0299_config alps_stv0299_config = { .volt13_op0_op1 = STV0299_VOLT13_OP1, .min_delay_ms = 100, .set_symbol_rate = alps_stv0299_set_symbol_rate, - .pll_set = philips_tsa5059_pll_set, }; -static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +static int ttusb_novas_grundig_29504_491_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) { struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv; u8 buf[4]; @@ -1355,6 +1338,8 @@ static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct buf[2] = 0x8e; buf[3] = 0x00; + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO; @@ -1364,10 +1349,9 @@ static int ttusb_novas_grundig_29504_491_pll_set(struct dvb_frontend *fe, struct static struct tda8083_config ttusb_novas_grundig_29504_491_config = { .demod_address = 0x68, - .pll_set = ttusb_novas_grundig_29504_491_pll_set, }; -static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) +static int alps_tdbe2_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend_parameters* params) { struct ttusb* ttusb = fe->dvb->priv; u32 div; @@ -1381,6 +1365,8 @@ static int alps_tdbe2_pll_set(struct dvb_frontend* fe, struct dvb_frontend_param data[2] = 0x85 | ((div >> 10) & 0x60); data[3] = (params->frequency < 174000000 ? 0x88 : params->frequency < 470000000 ? 0x84 : 0x81); + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); if (i2c_transfer (&ttusb->i2c_adap, &msg, 1) != 1) return -EIO; @@ -1393,7 +1379,6 @@ static struct ves1820_config alps_tdbe2_config = { .xin = 57840000UL, .invert = 1, .selagc = VES1820_SELAGC_SIGNAMPERR, - .pll_set = alps_tdbe2_pll_set, }; static u8 read_pwm(struct ttusb* ttusb) @@ -1410,6 +1395,174 @@ static u8 read_pwm(struct ttusb* ttusb) } +static int dvbc_philips_tdm1316l_tuner_set_params(struct dvb_frontend *fe, struct dvb_frontend_parameters *params) +{ + struct ttusb *ttusb = (struct ttusb *) fe->dvb->priv; + u8 tuner_buf[5]; + 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; + if (tuner_frequency < 87000000) {return -EINVAL;} + else if (tuner_frequency < 130000000) {cp = 3; band = 1;} + else if (tuner_frequency < 160000000) {cp = 5; band = 1;} + else if (tuner_frequency < 200000000) {cp = 6; band = 1;} + else if (tuner_frequency < 290000000) {cp = 3; band = 2;} + else if (tuner_frequency < 420000000) {cp = 5; band = 2;} + else if (tuner_frequency < 480000000) {cp = 6; band = 2;} + else if (tuner_frequency < 620000000) {cp = 3; band = 4;} + else if (tuner_frequency < 830000000) {cp = 5; band = 4;} + else if (tuner_frequency < 895000000) {cp = 7; band = 4;} + else {return -EINVAL;} + + // assume PLL filter should always be 8MHz for the moment. + filter = 1; + + // calculate divisor + // (Finput + Fif)/Fref; Fif = 36125000 Hz, Fref = 62500 Hz + tuner_frequency = ((params->frequency + 36125000) / 62500); + + // setup tuner buffer + tuner_buf[0] = tuner_frequency >> 8; + tuner_buf[1] = tuner_frequency & 0xff; + tuner_buf[2] = 0xc8; + tuner_buf[3] = (cp << 5) | (filter << 3) | band; + tuner_buf[4] = 0x80; + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { + printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 1\n"); + return -EIO; + } + + msleep(50); + + if (fe->ops.i2c_gate_ctrl) + fe->ops.i2c_gate_ctrl(fe, 1); + if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) { + printk("dvb-ttusb-budget: dvbc_philips_tdm1316l_pll_set Error 2\n"); + return -EIO; + } + + msleep(1); + + return 0; +} + +static u8 dvbc_philips_tdm1316l_inittab[] = { + 0x80, 0x21, + 0x80, 0x20, + 0x81, 0x01, + 0x81, 0x00, + 0x00, 0x09, + 0x01, 0x69, + 0x03, 0x00, + 0x04, 0x00, + 0x07, 0x00, + 0x08, 0x00, + 0x20, 0x00, + 0x21, 0x40, + 0x22, 0x00, + 0x23, 0x00, + 0x24, 0x40, + 0x25, 0x88, + 0x30, 0xff, + 0x31, 0x00, + 0x32, 0xff, + 0x33, 0x00, + 0x34, 0x50, + 0x35, 0x7f, + 0x36, 0x00, + 0x37, 0x20, + 0x38, 0x00, + 0x40, 0x1c, + 0x41, 0xff, + 0x42, 0x29, + 0x43, 0x20, + 0x44, 0xff, + 0x45, 0x00, + 0x46, 0x00, + 0x49, 0x04, + 0x4a, 0xff, + 0x4b, 0x7f, + 0x52, 0x30, + 0x55, 0xae, + 0x56, 0x47, + 0x57, 0xe1, + 0x58, 0x3a, + 0x5a, 0x1e, + 0x5b, 0x34, + 0x60, 0x00, + 0x63, 0x00, + 0x64, 0x00, + 0x65, 0x00, + 0x66, 0x00, + 0x67, 0x00, + 0x68, 0x00, + 0x69, 0x00, + 0x6a, 0x02, + 0x6b, 0x00, + 0x70, 0xff, + 0x71, 0x00, + 0x72, 0x00, + 0x73, 0x00, + 0x74, 0x0c, + 0x80, 0x00, + 0x81, 0x00, + 0x82, 0x00, + 0x83, 0x00, + 0x84, 0x04, + 0x85, 0x80, + 0x86, 0x24, + 0x87, 0x78, + 0x88, 0x00, + 0x89, 0x00, + 0x90, 0x01, + 0x91, 0x01, + 0xa0, 0x00, + 0xa1, 0x00, + 0xa2, 0x00, + 0xb0, 0x91, + 0xb1, 0x0b, + 0xc0, 0x4b, + 0xc1, 0x00, + 0xc2, 0x00, + 0xd0, 0x00, + 0xd1, 0x00, + 0xd2, 0x00, + 0xd3, 0x00, + 0xd4, 0x00, + 0xd5, 0x00, + 0xde, 0x00, + 0xdf, 0x00, + 0x61, 0x38, + 0x62, 0x0a, + 0x53, 0x13, + 0x59, 0x08, + 0x55, 0x00, + 0x56, 0x40, + 0x57, 0x08, + 0x58, 0x3d, + 0x88, 0x10, + 0xa0, 0x00, + 0xa0, 0x00, + 0xa0, 0x00, + 0xa0, 0x04, + 0xff, 0xff, +}; + +static struct stv0297_config dvbc_philips_tdm1316l_config = { + .demod_address = 0x1c, + .inittab = dvbc_philips_tdm1316l_inittab, + .invert = 0, +}; + static void frontend_init(struct ttusb* ttusb) { switch(le16_to_cpu(ttusb->dev->descriptor.idProduct)) { @@ -1417,11 +1570,13 @@ static void frontend_init(struct ttusb* ttusb) // try the stv0299 based first ttusb->fe = stv0299_attach(&alps_stv0299_config, &ttusb->i2c_adap); if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = philips_tsa5059_tuner_set_params; + if(ttusb->revision == TTUSB_REV_2_2) { // ALPS BSBE1 alps_stv0299_config.inittab = alps_bsbe1_inittab; - ttusb->fe->ops->set_voltage = lnbp21_set_voltage; + lnbp21_attach(ttusb->fe, &ttusb->i2c_adap, 0, 0); } else { // ALPS BSRU6 - ttusb->fe->ops->set_voltage = ttusb_set_voltage; + ttusb->fe->ops.set_voltage = ttusb_set_voltage; } break; } @@ -1429,28 +1584,41 @@ static void frontend_init(struct ttusb* ttusb) // Grundig 29504-491 ttusb->fe = tda8083_attach(&ttusb_novas_grundig_29504_491_config, &ttusb->i2c_adap); if (ttusb->fe != NULL) { - ttusb->fe->ops->set_voltage = ttusb_set_voltage; + ttusb->fe->ops.tuner_ops.set_params = ttusb_novas_grundig_29504_491_tuner_set_params; + ttusb->fe->ops.set_voltage = ttusb_set_voltage; break; } - break; case 0x1004: // Hauppauge/TT DVB-C budget (ves1820/ALPS TDBE2(sp5659)) ttusb->fe = ves1820_attach(&alps_tdbe2_config, &ttusb->i2c_adap, read_pwm(ttusb)); - if (ttusb->fe != NULL) + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = alps_tdbe2_tuner_set_params; + break; + } + + ttusb->fe = stv0297_attach(&dvbc_philips_tdm1316l_config, &ttusb->i2c_adap); + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = dvbc_philips_tdm1316l_tuner_set_params; break; + } break; 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) + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.set_params = alps_tdmb7_tuner_set_params; break; + } // Philips td1316 ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap); - if (ttusb->fe != NULL) + if (ttusb->fe != NULL) { + ttusb->fe->ops.tuner_ops.init = philips_tdm1316l_tuner_init; + ttusb->fe->ops.tuner_ops.set_params = philips_tdm1316l_tuner_set_params; break; + } break; } @@ -1461,8 +1629,8 @@ static void frontend_init(struct ttusb* ttusb) } 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); + if (ttusb->fe->ops.release) + ttusb->fe->ops.release(ttusb->fe); ttusb->fe = NULL; } } @@ -1507,7 +1675,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i mutex_unlock(&ttusb->semi2c); - if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE)) < 0) { + if ((result = dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE, &udev->dev)) < 0) { ttusb_free_iso_urbs(ttusb); kfree(ttusb); return result; diff --git a/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 44dea321184..6c1cb770bcf 100644 --- a/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -1432,7 +1432,7 @@ static int ttusb_dec_init_dvb(struct ttusb_dec *dec) dprintk("%s\n", __FUNCTION__); if ((result = dvb_register_adapter(&dec->adapter, - dec->model_name, THIS_MODULE)) < 0) { + dec->model_name, THIS_MODULE, &dec->udev->dev)) < 0) { printk("%s: dvb_register_adapter failed: error %d\n", __FUNCTION__, result); @@ -1657,8 +1657,8 @@ static int ttusb_dec_probe(struct usb_interface *intf, } 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); + if (dec->fe->ops.release) + dec->fe->ops.release(dec->fe); dec->fe = NULL; } } diff --git a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c index a5a46175fa0..42f39a89bc4 100644 --- a/drivers/media/dvb/ttusb-dec/ttusbdecfe.c +++ b/drivers/media/dvb/ttusb-dec/ttusbdecfe.c @@ -28,8 +28,6 @@ struct ttusbdecfe_state { - struct dvb_frontend_ops ops; - /* configuration settings */ const struct ttusbdecfe_config* config; @@ -203,10 +201,9 @@ struct dvb_frontend* ttusbdecfe_dvbt_attach(const struct ttusbdecfe_config* conf /* 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; + memcpy(&state->frontend.ops, &ttusbdecfe_dvbt_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; } @@ -226,10 +223,9 @@ struct dvb_frontend* ttusbdecfe_dvbs_attach(const struct ttusbdecfe_config* conf 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; + memcpy(&state->frontend.ops, &ttusbdecfe_dvbs_ops, sizeof(struct dvb_frontend_ops)); state->frontend.demodulator_priv = state; return &state->frontend; } |