Commit ea609508 authored by Michael Hunold's avatar Michael Hunold Committed by Linus Torvalds

[PATCH] dvb: follow frontend changes in drivers

- [DVB] dvb-ttusb-dec, dvb-ttusb-budget, skystar2, bt878 + dvb-bt8xx: follow
  frontend changes in driver

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