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 @@
#include "dvbdev.h"
#include "demux.h"
#include "dvb_net.h"
#include "stv0299.h"
#include "mt352.h"
static int debug;
......@@ -77,6 +79,9 @@ struct dmaq {
u8 *buffer;
};
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,9)
#define __iomem
#endif
struct adapter {
struct pci_dev *pdev;
......@@ -118,6 +123,9 @@ struct adapter {
int pid_count;
int whole_bandwidth_count;
u32 mac_filter;
struct dvb_frontend* fe;
int (*fe_sleep)(struct dvb_frontend* fe);
};
#define write_reg_dw(adapter,reg,value) writel(value, adapter->io_mem + reg)
......@@ -297,13 +305,6 @@ static int master_xfer(struct i2c_adapter* adapter, struct i2c_msg msgs[], int n
for (i = 0; i < num; i++) {
ddprintk("message %d: flags=0x%x, addr=0x%x, buf=0x%x, len=%d \n", i,
msgs[i].flags, msgs[i].addr, msgs[i].buf[0], msgs[i].len);
/* allow only the mt312, mt352 and stv0299 frontends to access the bus */
if ((msgs[i].addr != 0x0e) && (msgs[i].addr != 0x68) &&
(msgs[i].addr != 0x61) && (msgs[i].addr != 0x0f)) {
up(&tmp->i2c_sem);
return -EREMOTEIO;
}
}
// read command
......@@ -785,7 +786,7 @@ static int eeprom_read(struct adapter *adapter, u16 addr, u8 *buf, u16 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;
u8 sum;
......@@ -1773,6 +1774,7 @@ static void free_adapter_object(struct adapter *adapter)
if (adapter->io_mem)
iounmap(adapter->io_mem);
if (adapter != 0)
kfree(adapter);
}
......@@ -2024,6 +2026,7 @@ static int dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
return 0;
}
#if 0
/* lnb control */
static void set_tuner_tone(struct adapter *adapter, u8 tone)
{
......@@ -2058,6 +2061,7 @@ static void set_tuner_tone(struct adapter *adapter, u8 tone)
write_reg_dw(adapter, 0x200, 0x40ff8000);
}
}
#endif
static void set_tuner_polarity(struct adapter *adapter, u8 polarity)
{
......@@ -2085,6 +2089,7 @@ static void set_tuner_polarity(struct adapter *adapter, u8 polarity)
write_reg_dw(adapter, 0x204, var);
}
#if 0
static void diseqc_send_bit(struct adapter *adapter, int data)
{
set_tuner_tone(adapter, 1);
......@@ -2135,7 +2140,7 @@ static int send_diseqc_msg(struct 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) {
case FE_SET_TONE:
......@@ -2169,107 +2174,252 @@ int soft_diseqc(struct adapter *adapter, unsigned int cmd, void *arg)
return 0;
}
#endif
static int flexcop_diseqc_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
static int flexcop_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
struct adapter *adapter = fe->before_after_data;
struct dvb_frontend_info info;
struct adapter* adapter = (struct adapter*) fe->dvb->priv;
fe->ioctl(fe, FE_GET_INFO, &info);
dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
// we must use different DiSEqC hw
switch (voltage) {
case SEC_VOLTAGE_13:
dprintk("%s: SEC_VOLTAGE_13, %x\n", __FUNCTION__, SEC_VOLTAGE_13);
set_tuner_polarity(adapter, 1);
return 0;
if (strcmp(info.name, "Zarlink MT312") == 0) {
//VP310 using mt312 driver for tuning only: diseqc not wired
//use FCII instead
if (!soft_diseqc(adapter, cmd, arg))
case SEC_VOLTAGE_18:
dprintk("%s: SEC_VOLTAGE_18, %x\n", __FUNCTION__, SEC_VOLTAGE_18);
set_tuner_polarity(adapter, 2);
return 0;
default:
return -EINVAL;
}
}
switch (cmd) {
case FE_SLEEP:
static int flexcop_sleep(struct dvb_frontend* fe)
{
dprintk("%s: FE_SLEEP\n", __FUNCTION__);
struct adapter* adapter = (struct adapter*) fe->dvb->priv;
dprintk("%s: FE_SLEEP\n", __FUNCTION__);
set_tuner_polarity(adapter, 0);
// return -EOPNOTSUPP, to make DVB core also send "FE_SLEEP" command to frontend.
return -EOPNOTSUPP;
if (adapter->fe_sleep) return adapter->fe_sleep(fe);
return 0;
}
case FE_SET_VOLTAGE:
static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
{
dprintk("%s: FE_SET_VOLTAGE\n", __FUNCTION__);
printk("flexcop_i2c_func\n");
switch ((fe_sec_voltage_t) arg) {
case SEC_VOLTAGE_13:
return I2C_FUNC_I2C;
}
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;
}
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;
}
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;
}
u32 flexcop_i2c_func(struct i2c_adapter *adapter)
static struct mt352_config samsung_tdtc9251dh0_config = {
.demod_address = 0x0f,
.demod_init = samsung_tdtc9251dh0_demod_init,
.pll_set = samsung_tdtc9251dh0_pll_set,
};
static void frontend_init(struct adapter *skystar2)
{
printk("flexcop_i2c_func\n");
switch(skystar2->pdev->device) {
case 0x2103: // Technisat Skystar2 OR Technisat Airstar2
return I2C_FUNC_I2C;
// try the skystar2 first (stv0299/Samsung tbmu24112(sl1935))
skystar2->fe = stv0299_attach(&samsung_tbmu24112_config, &skystar2->i2c_adap);
if (skystar2->fe != NULL) {
skystar2->fe->ops->set_voltage = flexcop_set_voltage;
skystar2->fe_sleep = skystar2->fe->ops->sleep;
skystar2->fe->ops->sleep = flexcop_sleep;
break;
}
static struct i2c_algorithm flexcop_algo = {
.name = "flexcop i2c algorithm",
.id = I2C_ALGO_BIT,
.master_xfer = master_xfer,
.functionality = flexcop_i2c_func,
};
// try the airstar2 (mt352/Samsung tdtc9251dh0(??))
skystar2->fe = mt352_attach(&samsung_tdtc9251dh0_config, &skystar2->i2c_adap);
if (skystar2->fe != NULL) {
skystar2->fe->ops->info.frequency_min = 474000000;
skystar2->fe->ops->info.frequency_max = 858000000;
break;
}
break;
}
if (skystar2->fe == NULL) {
printk("skystar2: A frontend driver was not found for device %04x/%04x subsystem %04x/%04x\n",
skystar2->pdev->vendor,
skystar2->pdev->device,
skystar2->pdev->subsystem_vendor,
skystar2->pdev->subsystem_device);
} else {
if (dvb_register_frontend(skystar2->dvb_adapter, skystar2->fe)) {
printk("skystar2: Frontend registration failed!\n");
if (skystar2->fe->ops->release)
skystar2->fe->ops->release(skystar2->fe);
skystar2->fe = NULL;
}
}
}
static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
......@@ -2298,8 +2448,10 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter = (struct adapter *) pci_get_drvdata(pdev);
dvb_adapter->priv = adapter;
adapter->dvb_adapter = dvb_adapter;
init_MUTEX(&adapter->i2c_sem);
......@@ -2316,16 +2468,12 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
adapter->i2c_adap.algo = &flexcop_algo;
adapter->i2c_adap.algo_data = NULL;
adapter->i2c_adap.id = I2C_ALGO_BIT;
adapter->i2c_adap.client_register = client_register;
adapter->i2c_adap.client_unregister = client_unregister;
if (i2c_add_adapter(&adapter->i2c_adap) < 0) {
dvb_unregister_adapter (adapter->dvb_adapter);
return -ENOMEM;
}
dvb_add_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL, adapter);
dvbdemux = &adapter->demux;
dvbdemux->priv = (void *) adapter;
......@@ -2361,6 +2509,9 @@ static int skystar2_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return ret;
dvb_net_init(adapter->dvb_adapter, &adapter->dvbnet, &dvbdemux->dmx);
frontend_init(adapter);
return 0;
}
......@@ -2385,9 +2536,9 @@ static void skystar2_remove(struct pci_dev *pdev)
dvb_dmxdev_release(&adapter->dmxdev);
dvb_dmx_release(&adapter->demux);
if (adapter->dvb_adapter != NULL) {
dvb_remove_frontend_ioctls(adapter->dvb_adapter, flexcop_diseqc_ioctl, NULL);
if (adapter->fe != NULL) dvb_unregister_frontend(adapter->fe);
if (adapter->dvb_adapter != NULL) {
i2c_del_adapter(&adapter->i2c_adap);
dvb_unregister_adapter(adapter->dvb_adapter);
......@@ -2398,7 +2549,7 @@ static void skystar2_remove(struct pci_dev *pdev)
static struct pci_device_id skystar2_pci_tbl[] = {
{0x000013d0, 0x00002103, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000},
{0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, //FCIII
/* {0x000013d0, 0x00002200, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000}, UNDEFINED HARDWARE - mail linuxtv.org list */ //FCIII
{0,},
};
......
......@@ -44,7 +44,7 @@
#include "dmxdev.h"
#include "dvbdev.h"
#include "bt878.h"
#include "dst-bt878.h"
#include "dst_priv.h"
/**************************************/
......@@ -559,22 +559,11 @@ static struct pci_driver bt878_pci_driver = {
static int bt878_pci_driver_registered = 0;
/* This will be used later by dvb-bt8xx to only use the audio
* dma of certain cards */
int bt878_find_audio_dma(void)
{
// pci_register_driver(&bt878_pci_driver);
bt878_pci_driver_registered = 1;
return 0;
}
EXPORT_SYMBOL(bt878_find_audio_dma);
/*******************************/
/* Module management functions */
/*******************************/
int bt878_init_module(void)
static int bt878_init_module(void)
{
bt878_num = 0;
bt878_pci_driver_registered = 0;
......@@ -586,13 +575,13 @@ int bt878_init_module(void)
/*
bt878_check_chipset();
*/
/* later we register inside of bt878_find_audio_dma
/* later we register inside of bt878_find_audio_dma()
* because we may want to ignore certain cards */
bt878_pci_driver_registered = 1;
return pci_module_init(&bt878_pci_driver);
}
void bt878_cleanup_module(void)
static void bt878_cleanup_module(void)
{
if (bt878_pci_driver_registered) {
bt878_pci_driver_registered = 0;
......@@ -601,12 +590,10 @@ void bt878_cleanup_module(void)
return;
}
EXPORT_SYMBOL(bt878_init_module);
EXPORT_SYMBOL(bt878_cleanup_module);
module_init(bt878_init_module);
module_exit(bt878_cleanup_module);
//MODULE_AUTHOR("XXX");
MODULE_LICENSE("GPL");
/*
......
/*
/*
Frontend-driver for TwinHan DST Frontend
Copyright (C) 2003 Jamie Honan
......@@ -30,32 +30,23 @@
#include <asm/div64.h>
#include "dvb_frontend.h"
#include "dst-bt878.h"
#include "dst_priv.h"
#include "dst.h"
unsigned int dst_verbose = 0;
MODULE_PARM(dst_verbose, "i");
MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)");
unsigned int dst_debug = 0;
MODULE_PARM(dst_debug, "i");
MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)");
struct dst_state {
#define dprintk if (dst_debug) printk
struct i2c_adapter* i2c;
#define DST_I2C_ADDR 0x55
struct bt878* bt;
#define DST_TYPE_IS_SAT 0
#define DST_TYPE_IS_TERR 1
#define DST_TYPE_IS_CABLE 2
struct dvb_frontend_ops ops;
#define DST_TYPE_HAS_NEWTUNE 1
#define DST_TYPE_HAS_TS204 2
#define DST_TYPE_HAS_SYMDIV 4
/* configuration settings */
const struct dst_config* config;
#define HAS_LOCK 1
#define ATTEMPT_TUNE 2
#define HAS_POWER 4
struct dvb_frontend frontend;
struct dst_data {
/* private demodulator data */
u8 tx_tuna[10];
u8 rx_tuna[10];
u8 rxbuffer[10];
......@@ -75,57 +66,38 @@ struct dst_data {
unsigned long cur_jiff;
u8 k22;
fe_bandwidth_t bandwidth;
struct bt878 *bt;
struct i2c_adapter *i2c;
struct dvb_adapter *dvb;
};
static struct dvb_frontend_info dst_info_sat = {
.name = "DST SAT",
.type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 1000, /* kHz for QPSK frontends */
.frequency_tolerance = 29500,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
/* . symbol_rate_tolerance = ???,*/
.notifier_delay = 50, /* 1/20 s */
.caps = FE_CAN_FEC_AUTO | FE_CAN_QPSK
};
static unsigned int dst_verbose = 0;
module_param(dst_verbose, int, 0644);
MODULE_PARM_DESC(dst_verbose, "verbose startup messages, default is 1 (yes)");
static unsigned int dst_debug = 0;
module_param(dst_debug, int, 0644);
MODULE_PARM_DESC(dst_debug, "debug messages, default is 0 (no)");
static struct dvb_frontend_info dst_info_cable = {
.name = "DST CABLE",
.type = FE_QAM,
.frequency_stepsize = 62500,
.frequency_min = 51000000,
.frequency_max = 858000000,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
/* . symbol_rate_tolerance = ???,*/
.notifier_delay = 50, /* 1/20 s */
.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
};
#define dprintk if (dst_debug) printk
static struct dvb_frontend_info dst_info_terr = {
.name = "DST TERR",
.type = FE_OFDM,
.frequency_min = 137000000,
.frequency_max = 858000000,
.frequency_stepsize = 166667,
.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
};
#define DST_TYPE_IS_SAT 0
#define DST_TYPE_IS_TERR 1
#define DST_TYPE_IS_CABLE 2
#define DST_TYPE_HAS_NEWTUNE 1
#define DST_TYPE_HAS_TS204 2
#define DST_TYPE_HAS_SYMDIV 4
#define HAS_LOCK 1
#define ATTEMPT_TUNE 2
#define HAS_POWER 4
static void dst_packsize(struct dst_data *dst, int psize)
static void dst_packsize(struct dst_state* state, int psize)
{
union dst_gpio_packet bits;
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 bits;
......@@ -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.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);
return -EREMOTEIO;
}
......@@ -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.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);
return -EREMOTEIO;
}
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;
int err;
*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);
return -EREMOTEIO;
}
*result = (u8) rd_packet.rd.value;
return 0;
}
......@@ -170,16 +143,16 @@ static int dst_gpio_inb(struct dst_data *dst, u8 * result)
#define DST_I2C_ENABLE 1
#define DST_8820 2
static int dst_reset8820(struct dst_data *dst)
static int dst_reset8820(struct dst_state *state)
{
int retval;
/* pull 8820 gpio pin low, wait, high, wait, then low */
// dprintk ("%s: reset 8820\n", __FUNCTION__);
retval = dst_gpio_outb(dst, DST_8820, DST_8820, 0);
retval = dst_gpio_outb(state, DST_8820, DST_8820, 0);
if (retval < 0)
return retval;
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)
return retval;
/* wait for more feedback on what works here *
......@@ -191,12 +164,12 @@ static int dst_reset8820(struct dst_data *dst)
return 0;
}
static int dst_i2c_enable(struct dst_data *dst)
static int dst_i2c_enable(struct dst_state *state)
{
int retval;
/* pull I2C enable gpio pin low, wait */
// dprintk ("%s: i2c enable\n", __FUNCTION__);
retval = dst_gpio_outb(dst, ~0, DST_I2C_ENABLE, 0);
retval = dst_gpio_outb(state, ~0, DST_I2C_ENABLE, 0);
if (retval < 0)
return retval;
// dprintk ("%s: i2c enable delay\n", __FUNCTION__);
......@@ -204,12 +177,12 @@ static int dst_i2c_enable(struct dst_data *dst)
return 0;
}
static int dst_i2c_disable(struct dst_data *dst)
static int dst_i2c_disable(struct dst_state *state)
{
int retval;
/* release I2C enable gpio pin, wait */
// dprintk ("%s: i2c disable\n", __FUNCTION__);
retval = dst_gpio_outb(dst, ~0, 0, 0);
retval = dst_gpio_outb(state, ~0, 0, 0);
if (retval < 0)
return retval;
// dprintk ("%s: i2c disable delay\n", __FUNCTION__);
......@@ -217,29 +190,29 @@ static int dst_i2c_disable(struct dst_data *dst)
return 0;
}
static int dst_wait_dst_ready(struct dst_data *dst)
static int dst_wait_dst_ready(struct dst_state *state)
{
u8 reply;
int retval;
int i;
for (i = 0; i < 200; i++) {
retval = dst_gpio_inb(dst, &reply);
retval = dst_gpio_inb(state, &reply);
if (retval < 0)
return retval;
if ((reply & DST_I2C_ENABLE) == 0) {
dprintk("%s: dst wait ready after %d\n", __FUNCTION__, i);
return 1;
}
msleep(5);
msleep(10);
}
dprintk("%s: dst wait NOT ready after %d\n", __FUNCTION__, i);
return 0;
}
static int write_dst(struct dst_data *dst, u8 * data, u8 len)
static int write_dst(struct dst_state *state, u8 * data, u8 len)
{
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 cnt;
......@@ -254,11 +227,11 @@ static int write_dst(struct dst_data *dst, u8 * data, u8 len)
}
msleep(30);
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]);
dst_i2c_disable(dst);
dst_i2c_disable(state);
msleep(500);
dst_i2c_enable(dst);
dst_i2c_enable(state);
msleep(500);
continue;
} else
......@@ -269,17 +242,17 @@ static int write_dst(struct dst_data *dst, u8 * data, u8 len)
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 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]);
dst_i2c_disable(dst);
dst_i2c_enable(dst);
dst_i2c_disable(state);
dst_i2c_enable(state);
continue;
} else
break;
......@@ -296,34 +269,34 @@ static int read_dst(struct dst_data *dst, u8 * ret, u8 len)
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;
dst->frequency = freq;
state->frequency = 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;
if (freq < 950 || freq > 2150)
return -EINVAL;
val = &dst->tx_tuna[0];
val = &state->tx_tuna[0];
val[2] = (freq >> 8) & 0x7f;
val[3] = (u8) freq;
val[4] = 1;
val[8] &= ~4;
if (freq < 1531)
val[8] |= 4;
} else if (dst->dst_type == DST_TYPE_IS_TERR) {
} else if (state->dst_type == DST_TYPE_IS_TERR) {
freq = freq / 1000;
if (freq < 137000 || freq > 858000)
return -EINVAL;
val = &dst->tx_tuna[0];
val = &state->tx_tuna[0];
val[2] = (freq >> 16) & 0xff;
val[3] = (freq >> 8) & 0xff;
val[4] = (u8) freq;
val[5] = 0;
switch (dst->bandwidth) {
switch (state->bandwidth) {
case BANDWIDTH_6_MHZ:
val[6] = 6;
break;
......@@ -340,10 +313,10 @@ static int dst_set_freq(struct dst_data *dst, u32 freq)
val[7] = 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 */
freq = freq / 1000;
val = &dst->tx_tuna[0];
val = &state->tx_tuna[0];
val[2] = (freq >> 16) & 0xff;
val[3] = (freq >> 8) & 0xff;
val[4] = (u8) freq;
......@@ -352,16 +325,16 @@ static int dst_set_freq(struct dst_data *dst, u32 freq)
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;
dst->bandwidth = bandwidth;
state->bandwidth = bandwidth;
if (dst->dst_type != DST_TYPE_IS_TERR)
if (state->dst_type != DST_TYPE_IS_TERR)
return 0;
val = &dst->tx_tuna[0];
val = &state->tx_tuna[0];
switch (bandwidth) {
case BANDWIDTH_6_MHZ:
val[6] = 6;
......@@ -381,13 +354,13 @@ static int dst_set_bandwidth(struct dst_data *dst, fe_bandwidth_t bandwidth)
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;
dst->inversion = inversion;
state->inversion = inversion;
val = &dst->tx_tuna[0];
val = &state->tx_tuna[0];
val[8] &= ~0x80;
......@@ -403,34 +376,33 @@ static int dst_set_inversion(struct dst_data *dst, fe_spectral_inversion_t inver
return 0;
}
static int dst_set_fec(struct dst_data *dst, fe_code_rate_t fec)
static int dst_set_fec(struct dst_state* state, fe_code_rate_t fec)
{
dst->fec = fec;
state->fec = fec;
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;
u32 symcalc;
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;
}
// dprintk("%s: set srate %u\n", __FUNCTION__, srate);
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 <<= 20;
do_div(sval, 88000);
......@@ -450,7 +422,6 @@ static int dst_set_symbolrate(struct dst_data *dst, u32 srate)
return 0;
}
static u8 dst_check_sum(u8 * buf, u32 len)
{
u32 i;
......@@ -463,14 +434,14 @@ static u8 dst_check_sum(u8 * buf, u32 len)
return ((~val) + 1);
}
typedef struct dst_types {
struct dst_types {
char *mstr;
int offs;
u8 dst_type;
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-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},
......@@ -479,7 +450,7 @@ struct dst_types dst_tlist[] = {
{"DSTMCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
{"DSTFCI", 1, DST_TYPE_IS_SAT, DST_TYPE_HAS_NEWTUNE},
{"DCTNEW", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE},
{"DCT_CI", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204},
{"DCT-CI", 1, DST_TYPE_IS_CABLE, DST_TYPE_HAS_NEWTUNE | DST_TYPE_HAS_TS204},
{"DTTDIG", 1, DST_TYPE_IS_TERR, 0}
};
......@@ -518,7 +489,7 @@ static int dst_type_print(u8 type)
return 0;
}
static int dst_check_ci(struct dst_data *dst)
static int dst_check_ci(struct dst_state *state)
{
u8 txbuf[8];
u8 rxbuf[8];
......@@ -532,17 +503,17 @@ static int dst_check_ci(struct dst_data *dst)
txbuf[1] = 6;
txbuf[7] = dst_check_sum(txbuf, 7);
dst_i2c_enable(dst);
dst_reset8820(dst);
retval = write_dst(dst, txbuf, 8);
dst_i2c_enable(state);
dst_reset8820(state);
retval = write_dst(state, txbuf, 8);
if (retval < 0) {
dst_i2c_disable(dst);
dst_i2c_disable(state);
dprintk("%s: write not successful, maybe no card?\n", __FUNCTION__);
return retval;
}
msleep(3);
retval = read_dst(dst, rxbuf, 1);
dst_i2c_disable(dst);
retval = read_dst(state, rxbuf, 1);
dst_i2c_disable(state);
if (retval < 0) {
dprintk("%s: read not successful, maybe no card?\n", __FUNCTION__);
return retval;
......@@ -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]);
return retval;
}
if (!dst_wait_dst_ready(dst))
if (!dst_wait_dst_ready(state))
return 0;
// dst_i2c_enable(i2c); Dimitri
retval = read_dst(dst, rxbuf, 8);
dst_i2c_disable(dst);
retval = read_dst(state, rxbuf, 8);
dst_i2c_disable(state);
if (retval < 0) {
dprintk("%s: read not successful\n", __FUNCTION__);
return retval;
......@@ -581,32 +552,32 @@ static int dst_check_ci(struct dst_data *dst)
}
dst_type_print(use_dst_type);
dst->type_flags = use_type_flags;
dst->dst_type = use_dst_type;
dst_type_flags_print(dst->type_flags);
state->type_flags = use_type_flags;
state->dst_type = use_dst_type;
dst_type_flags_print(state->type_flags);
if (dst->type_flags & DST_TYPE_HAS_TS204) {
dst_packsize(dst, 204);
if (state->type_flags & DST_TYPE_HAS_TS204) {
dst_packsize(state, 204);
}
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;
u8 reply;
dst_i2c_enable(dst);
dst_reset8820(dst);
retval = write_dst(dst, data, len);
dst_i2c_enable(state);
dst_reset8820(state);
retval = write_dst(state, data, len);
if (retval < 0) {
dst_i2c_disable(dst);
dst_i2c_disable(state);
dprintk("%s: write not successful\n", __FUNCTION__);
return retval;
}
msleep(33);
retval = read_dst(dst, &reply, 1);
dst_i2c_disable(dst);
retval = read_dst(state, &reply, 1);
dst_i2c_disable(state);
if (retval < 0) {
dprintk("%s: read verify not successful\n", __FUNCTION__);
return retval;
......@@ -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))
return 0;
if (!dst_wait_dst_ready(dst))
if (!dst_wait_dst_ready(state))
return 0;
// dst_i2c_enable(i2c); Per dimitri
retval = read_dst(dst, dst->rxbuffer, 8);
dst_i2c_disable(dst);
retval = read_dst(state, state->rxbuffer, 8);
dst_i2c_disable(state);
if (retval < 0) {
dprintk("%s: read not successful\n", __FUNCTION__);
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__);
return 0;
}
return 0;
}
static int dst_get_signal(struct dst_data *dst)
static int dst_get_signal(struct dst_state* state)
{
int retval;
u8 get_signal[] = { 0x00, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfb };
if ((dst->diseq_flags & ATTEMPT_TUNE) == 0) {
dst->decode_lock = dst->decode_strength = dst->decode_snr = 0;
if ((state->diseq_flags & ATTEMPT_TUNE) == 0) {
state->decode_lock = state->decode_strength = state->decode_snr = 0;
return 0;
}
if (0 == (dst->diseq_flags & HAS_LOCK)) {
dst->decode_lock = dst->decode_strength = dst->decode_snr = 0;
if (0 == (state->diseq_flags & HAS_LOCK)) {
state->decode_lock = state->decode_strength = state->decode_snr = 0;
return 0;
}
if (time_after_eq(jiffies, dst->cur_jiff + (HZ / 5))) {
retval = dst_command(dst, get_signal, 8);
if (time_after_eq(jiffies, state->cur_jiff + (HZ / 5))) {
retval = dst_command(state, get_signal, 8);
if (retval < 0)
return retval;
if (dst->dst_type == DST_TYPE_IS_SAT) {
dst->decode_lock = ((dst->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
dst->decode_strength = dst->rxbuffer[5] << 8;
dst->decode_snr = dst->rxbuffer[2] << 8 | dst->rxbuffer[3];
} else if ((dst->dst_type == DST_TYPE_IS_TERR) || (dst->dst_type == DST_TYPE_IS_CABLE)) {
dst->decode_lock = (dst->rxbuffer[1]) ? 1 : 0;
dst->decode_strength = dst->rxbuffer[4] << 8;
dst->decode_snr = dst->rxbuffer[3] << 8;
if (state->dst_type == DST_TYPE_IS_SAT) {
state->decode_lock = ((state->rxbuffer[6] & 0x10) == 0) ? 1 : 0;
state->decode_strength = state->rxbuffer[5] << 8;
state->decode_snr = state->rxbuffer[2] << 8 | state->rxbuffer[3];
} else if ((state->dst_type == DST_TYPE_IS_TERR) || (state->dst_type == DST_TYPE_IS_CABLE)) {
state->decode_lock = (state->rxbuffer[1]) ? 1 : 0;
state->decode_strength = state->rxbuffer[4] << 8;
state->decode_snr = state->rxbuffer[3] << 8;
}
dst->cur_jiff = jiffies;
state->cur_jiff = jiffies;
}
return 0;
}
/*
* line22k0 0x00, 0x09, 0x00, 0xff, 0x01, 0x00, 0x00, 0x00
* line22k1 0x00, 0x09, 0x01, 0xff, 0x01, 0x00, 0x00, 0x00
* line22k2 0x00, 0x09, 0x02, 0xff, 0x01, 0x00, 0x00, 0x00
* tone 0x00, 0x09, 0xff, 0x00, 0x01, 0x00, 0x00, 0x00
* data 0x00, 0x09, 0xff, 0x01, 0x01, 0x00, 0x00, 0x00
* power_off 0x00, 0x09, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00
* power_on 0x00, 0x09, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00
* Diseqc 1 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec
* Diseqc 2 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf4, 0xe8
* Diseqc 3 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf8, 0xe4
* Diseqc 4 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xfc, 0xe0
*/
static int dst_set_diseqc(struct dst_data *dst, u8 * cmd, u8 len)
{
u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
if (dst->dst_type == DST_TYPE_IS_TERR)
return 0;
if (len == 0 || len > 4)
return -EINVAL;
memcpy(&paket[3], cmd, len);
paket[7] = dst_check_sum(&paket[0], 7);
dst_command(dst, paket, 8);
return 0;
}
static int dst_tone_power_cmd(struct dst_data *dst)
static int dst_tone_power_cmd(struct dst_state* state)
{
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;
if (dst->voltage == SEC_VOLTAGE_OFF)
if (state->voltage == SEC_VOLTAGE_OFF)
paket[4] = 0;
else
paket[4] = 1;
if (dst->tone == SEC_TONE_ON)
paket[2] = dst->k22;
if (state->tone == SEC_TONE_ON)
paket[2] = state->k22;
else
paket[2] = 0;
paket[7] = dst_check_sum(&paket[0], 7);
dst_command(dst, paket, 8);
return 0;
}
static int dst_set_voltage(struct dst_data *dst, fe_sec_voltage_t voltage)
{
u8 *val;
int need_cmd;
dst->voltage = voltage;
if (dst->dst_type == DST_TYPE_IS_TERR)
return 0;
need_cmd = 0;
val = &dst->tx_tuna[0];
val[8] &= ~0x40;
switch (voltage) {
case SEC_VOLTAGE_13:
if ((dst->diseq_flags & HAS_POWER) == 0)
need_cmd = 1;
dst->diseq_flags |= HAS_POWER;
break;
case SEC_VOLTAGE_18:
if ((dst->diseq_flags & HAS_POWER) == 0)
need_cmd = 1;
dst->diseq_flags |= HAS_POWER;
val[8] |= 0x40;
break;
case SEC_VOLTAGE_OFF:
need_cmd = 1;
dst->diseq_flags &= ~(HAS_POWER | HAS_LOCK | ATTEMPT_TUNE);
break;
default:
return -EINVAL;
}
if (need_cmd) {
dst_tone_power_cmd(dst);
}
return 0;
}
static int dst_set_tone(struct dst_data *dst, fe_sec_tone_mode_t tone)
{
u8 *val;
dst->tone = tone;
if (dst->dst_type == DST_TYPE_IS_TERR)
return 0;
val = &dst->tx_tuna[0];
val[8] &= ~0x1;
switch (tone) {
case SEC_TONE_OFF:
break;
case SEC_TONE_ON:
val[8] |= 1;
break;
default:
return -EINVAL;
}
dst_tone_power_cmd(dst);
dst_command(state, paket, 8);
return 0;
}
static int dst_get_tuna(struct dst_data *dst)
static int dst_get_tuna(struct dst_state* state)
{
int retval;
if ((dst->diseq_flags & ATTEMPT_TUNE) == 0)
if ((state->diseq_flags & ATTEMPT_TUNE) == 0)
return 0;
dst->diseq_flags &= ~(HAS_LOCK);
if (!dst_wait_dst_ready(dst))
state->diseq_flags &= ~(HAS_LOCK);
if (!dst_wait_dst_ready(state))
return 0;
if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) {
if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
/* how to get variable length reply ???? */
retval = read_dst(dst, dst->rx_tuna, 10);
retval = read_dst(state, state->rx_tuna, 10);
} else {
retval = read_dst(dst, &dst->rx_tuna[2], 8);
retval = read_dst(state, &state->rx_tuna[2], 8);
}
if (retval < 0) {
dprintk("%s: read not successful\n", __FUNCTION__);
return 0;
}
if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) {
if (dst->rx_tuna[9] != dst_check_sum(&dst->rx_tuna[0], 9)) {
if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
if (state->rx_tuna[9] != dst_check_sum(&state->rx_tuna[0], 9)) {
dprintk("%s: checksum failure?\n", __FUNCTION__);
return 0;
}
} else {
if (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__);
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;
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->rx_tuna[5]);
......@@ -819,41 +696,44 @@ static int dst_get_tuna(struct dst_data *dst)
dst->decode_n2 = (dst->rx_tuna[8] << 8) +
(dst->rx_tuna[7]);
*/
dst->diseq_flags |= HAS_LOCK;
state->diseq_flags |= HAS_LOCK;
/* dst->cur_jiff = jiffies; */
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;
u8 reply;
dprintk("%s: type_flags 0x%x \n", __FUNCTION__, dst->type_flags);
dst->decode_freq = 0;
dst->decode_lock = dst->decode_strength = dst->decode_snr = 0;
if (dst->dst_type == DST_TYPE_IS_SAT) {
if (!(dst->diseq_flags & HAS_POWER))
dst_set_voltage(dst, SEC_VOLTAGE_13);
dprintk("%s: type_flags 0x%x \n", __FUNCTION__, state->type_flags);
state->decode_freq = 0;
state->decode_lock = state->decode_strength = state->decode_snr = 0;
if (state->dst_type == DST_TYPE_IS_SAT) {
if (!(state->diseq_flags & HAS_POWER))
dst_set_voltage(fe, SEC_VOLTAGE_13);
}
dst->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
dst_i2c_enable(dst);
if (dst->type_flags & DST_TYPE_HAS_NEWTUNE) {
dst_reset8820(dst);
dst->tx_tuna[9] = dst_check_sum(&dst->tx_tuna[0], 9);
retval = write_dst(dst, &dst->tx_tuna[0], 10);
state->diseq_flags &= ~(HAS_LOCK | ATTEMPT_TUNE);
dst_i2c_enable(state);
if (state->type_flags & DST_TYPE_HAS_NEWTUNE) {
dst_reset8820(state);
state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[0], 9);
retval = write_dst(state, &state->tx_tuna[0], 10);
} else {
dst->tx_tuna[9] = dst_check_sum(&dst->tx_tuna[2], 7);
retval = write_dst(dst, &dst->tx_tuna[2], 8);
state->tx_tuna[9] = dst_check_sum(&state->tx_tuna[2], 7);
retval = write_dst(state, &state->tx_tuna[2], 8);
}
if (retval < 0) {
dst_i2c_disable(dst);
dst_i2c_disable(state);
dprintk("%s: write not successful\n", __FUNCTION__);
return retval;
}
msleep(3);
retval = read_dst(dst, &reply, 1);
dst_i2c_disable(dst);
retval = read_dst(state, &reply, 1);
dst_i2c_disable(state);
if (retval < 0) {
dprintk("%s: read verify not successful\n", __FUNCTION__);
return retval;
......@@ -862,395 +742,348 @@ static int dst_write_tuna(struct dst_data *dst)
dprintk("%s: write reply not 0xff 0x%02x \n", __FUNCTION__, reply);
return 0;
}
dst->diseq_flags |= ATTEMPT_TUNE;
return dst_get_tuna(dst);
state->diseq_flags |= ATTEMPT_TUNE;
return dst_get_tuna(state);
}
static void dst_init(struct dst_data *dst)
{
static u8 ini_satci_tuna[] = { 9, 0, 3, 0xb6, 1, 0, 0x73, 0x21, 0, 0 };
static u8 ini_satfta_tuna[] = { 0, 0, 3, 0xb6, 1, 0x55, 0xbd, 0x50, 0, 0 };
static u8 ini_tvfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
static u8 ini_tvci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
static u8 ini_cabfta_tuna[] = { 0, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
static u8 ini_cabci_tuna[] = { 9, 0, 3, 0xb6, 1, 7, 0x0, 0x0, 0, 0 };
dst->inversion = INVERSION_ON;
dst->voltage = SEC_VOLTAGE_13;
dst->tone = SEC_TONE_OFF;
dst->symbol_rate = 29473000;
dst->fec = FEC_AUTO;
dst->diseq_flags = 0;
dst->k22 = 0x02;
dst->bandwidth = BANDWIDTH_7_MHZ;
dst->cur_jiff = jiffies;
if (dst->dst_type == DST_TYPE_IS_SAT) {
dst->frequency = 950000;
memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_satci_tuna : ini_satfta_tuna), sizeof(ini_satfta_tuna));
} else if (dst->dst_type == DST_TYPE_IS_TERR) {
dst->frequency = 137000000;
memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_tvci_tuna : ini_tvfta_tuna), sizeof(ini_tvfta_tuna));
} else if (dst->dst_type == DST_TYPE_IS_CABLE) {
dst->frequency = 51000000;
memcpy(dst->tx_tuna, ((dst->type_flags & DST_TYPE_HAS_NEWTUNE) ? ini_cabci_tuna : ini_cabfta_tuna), sizeof(ini_cabfta_tuna));
}
}
/*
* 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
*/
struct lkup {
unsigned int cmd;
char *desc;
} looker[] = {
{
FE_GET_INFO, "FE_GET_INFO:"}, {
FE_READ_STATUS, "FE_READ_STATUS:"}, {
FE_READ_BER, "FE_READ_BER:"}, {
FE_READ_SIGNAL_STRENGTH, "FE_READ_SIGNAL_STRENGTH:"}, {
FE_READ_SNR, "FE_READ_SNR:"}, {
FE_READ_UNCORRECTED_BLOCKS, "FE_READ_UNCORRECTED_BLOCKS:"}, {
FE_SET_FRONTEND, "FE_SET_FRONTEND:"}, {
FE_GET_FRONTEND, "FE_GET_FRONTEND:"}, {
FE_SLEEP, "FE_SLEEP:"}, {
FE_INIT, "FE_INIT:"}, {
FE_SET_TONE, "FE_SET_TONE:"}, {
FE_SET_VOLTAGE, "FE_SET_VOLTAGE:"},};
static int dst_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
static int dst_set_diseqc(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd)
{
struct dst_data *dst = fe->data;
int retval;
/*
char *cc;
cc = "FE_UNSUPP:";
for(retval = 0; retval < sizeof(looker) / sizeof(looker[0]); retval++) {
if (looker[retval].cmd == cmd) {
cc = looker[retval].desc;
break;
}
}
dprintk("%s cmd %s (0x%x)\n",__FUNCTION__, cc, cmd);
*/
// printk("%s: dst %8.8x bt %8.8x i2c %8.8x\n", __FUNCTION__, dst, dst->bt, dst->i2c);
/* should be set by attach, but just in case */
switch (cmd) {
case FE_GET_INFO:
{
struct dvb_frontend_info *info;
info = &dst_info_sat;
if (dst->dst_type == DST_TYPE_IS_TERR)
info = &dst_info_terr;
else if (dst->dst_type == DST_TYPE_IS_CABLE)
info = &dst_info_cable;
memcpy(arg, info, sizeof(struct dvb_frontend_info));
break;
}
case FE_READ_STATUS:
{
fe_status_t *status = arg;
*status = 0;
if (dst->diseq_flags & HAS_LOCK) {
dst_get_signal(dst);
if (dst->decode_lock)
*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
}
break;
}
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
u8 paket[8] = { 0x00, 0x08, 0x04, 0xe0, 0x10, 0x38, 0xf0, 0xec };
case FE_READ_BER:
{
/* guess */
// *(u32*) arg = dst->decode_n1;
*(u32 *) arg = 0;
return -EOPNOTSUPP;
}
if (state->dst_type == DST_TYPE_IS_TERR)
return 0;
case FE_READ_SIGNAL_STRENGTH:
{
dst_get_signal(dst);
*((u16 *) arg) = dst->decode_strength;
break;
}
if (cmd->msg_len == 0 || cmd->msg_len > 4)
return -EINVAL;
memcpy(&paket[3], cmd->msg, cmd->msg_len);
paket[7] = dst_check_sum(&paket[0], 7);
dst_command(state, paket, 8);
return 0;
}
case FE_READ_SNR:
{
dst_get_signal(dst);
*((u16 *) arg) = dst->decode_snr;
break;
}
static int dst_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
u8 *val;
int need_cmd;
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
case FE_READ_UNCORRECTED_BLOCKS:
{
*((u32 *) arg) = 0; /* the stv0299 can't measure BER and */
return -EOPNOTSUPP; /* errors at the same time.... */
}
state->voltage = voltage;
case FE_SET_FRONTEND:
{
struct dvb_frontend_parameters *p = arg;
dst_set_freq(dst, p->frequency);
dst_set_inversion(dst, p->inversion);
if (dst->dst_type == DST_TYPE_IS_SAT) {
dst_set_fec(dst, p->u.qpsk.fec_inner);
dst_set_symbolrate(dst, p->u.qpsk.symbol_rate);
} else if (dst->dst_type == DST_TYPE_IS_TERR) {
dst_set_bandwidth(dst, p->u.ofdm.bandwidth);
} else if (dst->dst_type == DST_TYPE_IS_CABLE) {
dst_set_fec(dst, p->u.qam.fec_inner);
dst_set_symbolrate(dst, p->u.qam.symbol_rate);
}
dst_write_tuna(dst);
if (state->dst_type == DST_TYPE_IS_TERR)
return 0;
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:
{
struct dvb_frontend_parameters *p = arg;
p->frequency = dst->decode_freq;
p->inversion = dst->inversion;
if (dst->dst_type == DST_TYPE_IS_SAT) {
p->u.qpsk.symbol_rate = dst->symbol_rate;
p->u.qpsk.fec_inner = dst_get_fec(dst);
} else if (dst->dst_type == DST_TYPE_IS_TERR) {
p->u.ofdm.bandwidth = dst->bandwidth;
} else if (dst->dst_type == DST_TYPE_IS_CABLE) {
p->u.qam.symbol_rate = dst->symbol_rate;
p->u.qam.fec_inner = dst_get_fec(dst);
p->u.qam.modulation = QAM_AUTO;
}
break;
}
static int dst_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
u8 *val;
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
state->tone = tone;
case FE_SLEEP:
if (state->dst_type == DST_TYPE_IS_TERR)
return 0;
case FE_INIT:
dst_init(dst);
break;
val = &state->tx_tuna[0];
case FE_DISEQC_SEND_MASTER_CMD:
{
struct dvb_diseqc_master_cmd *cmd = (struct dvb_diseqc_master_cmd *) arg;
retval = dst_set_diseqc(dst, cmd->msg, cmd->msg_len);
if (retval < 0)
return retval;
break;
}
case FE_SET_TONE:
retval = dst_set_tone(dst, (fe_sec_tone_mode_t) arg);
if (retval < 0)
return retval;
val[8] &= ~0x1;
switch (tone) {
case SEC_TONE_OFF:
break;
case FE_SET_VOLTAGE:
retval = dst_set_voltage(dst, (fe_sec_voltage_t) arg);
if (retval < 0)
return retval;
case SEC_TONE_ON:
val[8] |= 1;
break;
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;
}
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_data *dst = (struct dst_data *) i2c_get_clientdata(client);
return sprintf(buf, "0x%02x\n", dst->dst_type);
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
*status = 0;
if (state->diseq_flags & HAS_LOCK) {
dst_get_signal(state);
if (state->decode_lock)
*status |= FE_HAS_LOCK | FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_SYNC | FE_HAS_VITERBI;
}
return 0;
}
static 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_data *dst = (struct dst_data *) i2c_get_clientdata(client);
unsigned long type;
type = simple_strtoul(buf, NULL, 0);
dst->dst_type = type & 0xff;
return strlen(buf) + 1;
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
dst_get_signal(state);
*strength = state->decode_strength;
return 0;
}
/* dst_type, "Type of DST card, 0 Satellite, 1 terrestial, 2 Cable, default driver determined"); */
static struct device_attribute dev_attr_client_type = {
.attr = {.name = "type",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE},
.show = &attr_read_type,
.store = &attr_write_type,
};
static int dst_read_snr(struct dvb_frontend* fe, u16* snr)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
dst_get_signal(state);
*snr = state->decode_snr;
return 0;
}
static 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_data *dst = (struct dst_data *) i2c_get_clientdata(client);
return sprintf(buf, "0x%02x\n", dst->type_flags);
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
dst_set_freq(state, p->frequency);
dst_set_inversion(state, p->inversion);
if (state->dst_type == DST_TYPE_IS_SAT) {
dst_set_fec(state, p->u.qpsk.fec_inner);
dst_set_symbolrate(state, p->u.qpsk.symbol_rate);
} else if (state->dst_type == DST_TYPE_IS_TERR) {
dst_set_bandwidth(state, p->u.ofdm.bandwidth);
} else if (state->dst_type == DST_TYPE_IS_CABLE) {
dst_set_fec(state, p->u.qam.fec_inner);
dst_set_symbolrate(state, p->u.qam.symbol_rate);
}
dst_write_tuna(fe);
return 0;
}
static 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_data *dst = (struct dst_data *) i2c_get_clientdata(client);
unsigned long flags;
flags = simple_strtoul(buf, NULL, 0);
dst->type_flags = flags & 0xffffffff;
return strlen(buf) + 1;
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
p->frequency = state->decode_freq;
p->inversion = state->inversion;
if (state->dst_type == DST_TYPE_IS_SAT) {
p->u.qpsk.symbol_rate = state->symbol_rate;
p->u.qpsk.fec_inner = dst_get_fec(state);
} else if (state->dst_type == DST_TYPE_IS_TERR) {
p->u.ofdm.bandwidth = state->bandwidth;
} else if (state->dst_type == DST_TYPE_IS_CABLE) {
p->u.qam.symbol_rate = state->symbol_rate;
p->u.qam.fec_inner = dst_get_fec(state);
p->u.qam.modulation = QAM_AUTO;
}
return 0;
}
/* dst_type_flags, "Type flags of DST card, bitfield 1=10 byte tuner, 2=TS is 204, 4=symdiv"); */
static struct device_attribute dev_attr_client_flags = {
.attr = {.name = "flags",.mode = S_IRUGO | S_IWUGO,.owner = THIS_MODULE},
.show = &attr_read_flags,
.store = &attr_write_flags,
};
static void dst_release(struct dvb_frontend* fe)
{
struct dst_state* state = (struct dst_state*) fe->demodulator_priv;
kfree(state);
}
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_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;
}
struct dst_state* state = NULL;
memset(dst, 0, sizeof(*dst));
dst->bt = bt;
dst->i2c = adapter;
if (dst_check_ci(dst) < 0) {
kfree(dst);
return -ENODEV;
}
dst_init(dst);
/* allocate memory for the internal state */
state = (struct dst_state*) kmalloc(sizeof(struct dst_state), GFP_KERNEL);
if (state == NULL) goto error;
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:
info = &dst_info_terr;
memcpy(&state->ops, &dst_dvbt_ops, sizeof(struct dvb_frontend_ops));
break;
case DST_TYPE_IS_CABLE:
info = &dst_info_cable;
memcpy(&state->ops, &dst_dvbc_ops, sizeof(struct dvb_frontend_ops));
break;
case DST_TYPE_IS_SAT:
info = &dst_info_sat;
memcpy(&state->ops, &dst_dvbs_ops, sizeof(struct dvb_frontend_ops));
break;
default:
printk("dst: unknown frontend type. please report to the LinuxTV.org DVB mailinglist.\n");
kfree(dst);
return -ENODEV;
goto error;
}
if (NULL == (client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
kfree(dst);
return -ENOMEM;
}
/* create dvb_frontend */
state->frontend.ops = &state->ops;
state->frontend.demodulator_priv = state;
return &state->frontend;
memcpy(client, &client_template, sizeof(struct i2c_client));
client->adapter = adapter;
client->addr = DST_I2C_ADDR;
error:
if (state) kfree(state);
return NULL;
}
i2c_set_clientdata(client, (void *) dst);
static struct dvb_frontend_ops dst_dvbt_ops = {
ret = i2c_attach_client(client);
if (ret) {
kfree(client);
kfree(dst);
return -EFAULT;
}
.info = {
.name = "DST DVB-T",
.type = FE_OFDM,
.frequency_min = 137000000,
.frequency_max = 858000000,
.frequency_stepsize = 166667,
.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
},
BUG_ON(!dst->dvb);
.release = dst_release,
device_create_file(&client->dev, &dev_attr_client_type);
device_create_file(&client->dev, &dev_attr_client_flags);
.init = dst_init,
ret = dvb_register_frontend(dst_ioctl, dst->dvb, dst, info, THIS_MODULE);
if (ret) {
i2c_detach_client(client);
kfree(client);
kfree(dst);
return -EFAULT;
}
.set_frontend = dst_set_frontend,
.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 detach_client(struct i2c_client *client)
{
struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client);
static struct dvb_frontend_ops dst_dvbs_ops = {
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);
device_remove_file(&client->dev, &dev_attr_client_flags);
.release = dst_release,
i2c_detach_client(client);
BUG_ON(state->dvb);
.init = dst_init,
kfree(client);
kfree(state);
.set_frontend = dst_set_frontend,
.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)
{
struct dst_data *state = (struct dst_data *) i2c_get_clientdata(client);
.diseqc_send_master_cmd = dst_set_diseqc,
.set_voltage = dst_set_voltage,
.set_tone = dst_set_tone,
};
switch (cmd) {
case FE_REGISTER:
state->dvb = (struct dvb_adapter *) arg;
break;
case FE_UNREGISTER:
state->dvb = NULL;
break;
default:
return -EOPNOTSUPP;
}
return 0;
}
static struct dvb_frontend_ops dst_dvbc_ops = {
static struct i2c_driver driver = {
.owner = THIS_MODULE,
.name = "dst",
.id = I2C_DRIVERID_DVBFE_DST,
.flags = I2C_DF_NOTIFY,
.attach_adapter = attach_adapter,
.detach_client = detach_client,
.command = command,
};
.info = {
.name = "DST DVB-C",
.type = FE_QAM,
.frequency_stepsize = 62500,
.frequency_min = 51000000,
.frequency_max = 858000000,
.symbol_rate_min = 1000000,
.symbol_rate_max = 45000000,
/* . symbol_rate_tolerance = ???,*/
.caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO
},
static struct i2c_client client_template = {
I2C_DEVNAME("dst"),
.flags = I2C_CLIENT_ALLOW_USE,
.driver = &driver,
};
.release = dst_release,
static int __init init_dst(void)
{
return i2c_add_driver(&driver);
}
.init = dst_init,
static void __exit exit_dst(void)
{
if (i2c_del_driver(&driver))
printk("dst: driver deregistration failed\n");
}
.set_frontend = dst_set_frontend,
.get_frontend = dst_get_frontend,
module_init(init_dst);
module_exit(exit_dst);
.read_status = dst_read_status,
.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_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 {
#define DST_IG_READ 2
#define DST_IG_TS 3
struct bt878 ;
struct bt878;
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
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;
......@@ -136,6 +415,7 @@ static int __init dvb_bt8xx_load_card( struct dvb_bt8xx_card *card)
return result;
}
card->dvb_adapter->priv = card;
card->bt->adapter = card->i2c_adapter;
......@@ -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);
frontend_init(card, type);
return 0;
}
......@@ -228,7 +510,7 @@ static int dvb_bt8xx_probe(struct device *dev)
switch(sub->core->type)
{
case BTTV_PINNACLESAT:
/* case BTTV_PINNACLESAT: UNDEFINED HARDWARE */
#ifdef BTTV_DVICO_DVBT_LITE
case BTTV_DVICO_DVBT_LITE:
#endif
......@@ -240,7 +522,11 @@ static int dvb_bt8xx_probe(struct device *dev)
* DA_APP(parallel) */
break;
#ifdef BTTV_TWINHAN_VP3021
case BTTV_TWINHAN_VP3021:
#else
case BTTV_NEBULA_DIGITV:
#endif
case BTTV_AVDVBT_761:
card->gpio_mode = (1 << 26) | (1 << 14) | (1 << 5);
card->op_sync_orin = 0;
......@@ -302,7 +588,7 @@ static int dvb_bt8xx_probe(struct device *dev)
init_MUTEX(&card->bt->gpio_lock);
card->bt->bttv_nr = sub->core->nr;
if ( (ret = dvb_bt8xx_load_card(card)) ) {
if ( (ret = dvb_bt8xx_load_card(card, sub->core->type)) ) {
kfree(card);
return ret;
}
......@@ -324,6 +610,7 @@ static int dvb_bt8xx_remove(struct device *dev)
card->demux.dmx.remove_frontend(&card->demux.dmx, &card->fe_hw);
dvb_dmxdev_release(&card->dmxdev);
dvb_dmx_release(&card->demux);
if (card->fe) dvb_unregister_frontend(card->fe);
dvb_unregister_adapter(card->dvb_adapter);
kfree(card);
......@@ -331,24 +618,6 @@ static int dvb_bt8xx_remove(struct device *dev)
return 0;
}
static void dvb_bt8xx_i2c_info(struct bttv_sub_device *sub,
struct i2c_client *client, int attach)
{
struct dvb_bt8xx_card *card = dev_get_drvdata(&sub->dev);
if (attach) {
printk("xxx attach\n");
if (client->driver->command)
client->driver->command(client, FE_REGISTER,
card->dvb_adapter);
} else {
printk("xxx detach\n");
if (client->driver->command)
client->driver->command(client, FE_UNREGISTER,
card->dvb_adapter);
}
}
static struct bttv_sub_driver driver = {
.drv = {
.name = "dvb-bt8xx",
......@@ -360,7 +629,6 @@ static struct bttv_sub_driver driver = {
* .resume = dvb_bt8xx_resume,
*/
},
.i2c_info = dvb_bt8xx_i2c_info,
};
static int __init dvb_bt8xx_init(void)
......
......@@ -26,6 +26,10 @@
#include "dvbdev.h"
#include "dvb_net.h"
#include "bttv.h"
#include "mt352.h"
#include "sp887x.h"
#include "dst.h"
#include "nxt6000.h"
struct dvb_bt8xx_card {
struct semaphore lock;
......@@ -44,4 +48,5 @@ struct dvb_bt8xx_card {
struct i2c_adapter *i2c_adapter;
struct dvb_net dvbnet;
struct dvb_frontend* fe;
};
......@@ -24,6 +24,8 @@
#include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_net.h"
#include "cx22700.h"
#include "tda1004x.h"
#include <linux/dvb/frontend.h>
#include <linux/dvb/dmx.h>
......@@ -132,6 +134,8 @@ struct ttusb {
#if 0
devfs_handle_t stc_devfs_handle;
#endif
struct dvb_frontend* fe;
};
/* ugly workaround ... don't know why it's neccessary to read */
......@@ -461,9 +465,10 @@ static int ttusb_init_controller(struct ttusb *ttusb)
}
#ifdef TTUSB_DISEQC
static int ttusb_send_diseqc(struct ttusb *ttusb,
static int ttusb_send_diseqc(struct dvb_frontend* fe,
const struct dvb_diseqc_master_cmd *cmd)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 b[12] = { 0xaa, ++ttusb->c, 0x18 };
int err;
......@@ -484,6 +489,7 @@ static int ttusb_send_diseqc(struct ttusb *ttusb,
}
#endif
#if 0
static int ttusb_update_lnb(struct ttusb *ttusb)
{
u8 b[] = { 0xaa, ++ttusb->c, 0x16, 5, /*power: */ 1,
......@@ -501,41 +507,25 @@ static int ttusb_update_lnb(struct ttusb *ttusb)
return err;
}
static int ttusb_set_voltage(struct ttusb *ttusb, fe_sec_voltage_t voltage)
static int ttusb_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
ttusb->voltage = voltage;
return ttusb_update_lnb(ttusb);
}
#ifdef TTUSB_TONE
static int ttusb_set_tone(struct ttusb *ttusb, fe_sec_tone_mode_t tone)
static int ttusb_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
ttusb->tone = tone;
return ttusb_update_lnb(ttusb);
}
#endif
static int ttusb_lnb_ioctl(struct dvb_frontend *fe, unsigned int cmd, void *arg)
{
struct ttusb *ttusb = fe->before_after_data;
switch (cmd) {
case FE_SET_VOLTAGE:
return ttusb_set_voltage(ttusb, (fe_sec_voltage_t) arg);
#ifdef TTUSB_TONE
case FE_SET_TONE:
return ttusb_set_tone(ttusb, (fe_sec_tone_mode_t) arg);
#endif
#ifdef TTUSB_DISEQC
case FE_DISEQC_SEND_MASTER_CMD:
return ttusb_send_diseqc(ttusb,
(struct dvb_diseqc_master_cmd *)
arg);
#endif
default:
return -EOPNOTSUPP;
};
}
#if 0
static void ttusb_set_led_freq(struct ttusb *ttusb, u8 freq)
......@@ -560,7 +550,7 @@ static void ttusb_handle_sec_data(struct ttusb_channel *channel,
const u8 * data, int len);
#endif
int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid;
static int numpkt = 0, lastj, numts, numstuff, numsec, numinvalid;
static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
int len)
......@@ -1071,38 +1061,183 @@ static struct file_operations stc_fops = {
};
#endif
u32 functionality(struct i2c_adapter *adapter)
static u32 functionality(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
}
static struct i2c_algorithm ttusb_dec_algo = {
.name = "ttusb dec i2c algorithm",
.id = I2C_ALGO_BIT,
.master_xfer = master_xfer,
.functionality = functionality,
};
static int client_register(struct i2c_client *client)
static int alps_tdmb7_pll_set(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
{
struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter);
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
u8 data[4];
struct i2c_msg msg = {.addr=0x61, .flags=0, .buf=data, .len=sizeof(data) };
u32 div;
div = (params->frequency + 36166667) / 166667;
if (client->driver->command)
return client->driver->command(client, FE_REGISTER, ttusb->adapter);
data[0] = (div >> 8) & 0x7f;
data[1] = div & 0xff;
data[2] = ((div >> 10) & 0x60) | 0x85;
data[3] = params->frequency < 592000000 ? 0x40 : 0x80;
if (i2c_transfer(&ttusb->i2c_adap, &msg, 1) != 1) return -EIO;
return 0;
}
static int client_unregister(struct i2c_client *client)
struct cx22700_config alps_tdmb7_config = {
.demod_address = 0x43,
.pll_set = alps_tdmb7_pll_set,
};
static int philips_tdm1316l_pll_init(struct dvb_frontend* fe)
{
struct ttusb *ttusb = (struct ttusb*)i2c_get_adapdata(client->adapter);
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
static u8 td1316_init[] = { 0x0b, 0xf5, 0x85, 0xab };
static u8 disable_mc44BC374c[] = { 0x1d, 0x74, 0xa0, 0x68 };
struct i2c_msg tuner_msg = { .addr=0x60, .flags=0, .buf=td1316_init, .len=sizeof(td1316_init) };
// setup PLL configuration
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
msleep(1);
// disable the mc44BC374c (do not check for errors)
tuner_msg.addr = 0x65;
tuner_msg.buf = disable_mc44BC374c;
tuner_msg.len = sizeof(disable_mc44BC374c);
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) {
i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1);
}
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)
return client->driver->command(client, FE_UNREGISTER, ttusb->adapter);
// calculate divisor
// ((36130000+((1000000/6)/2)) + Finput)/(1000000/6)
tuner_frequency = (((params->frequency / 1000) * 6) + 217280) / 1000;
// setup tuner buffer
tuner_buf[0] = tuner_frequency >> 8;
tuner_buf[1] = tuner_frequency & 0xff;
tuner_buf[2] = 0xca;
tuner_buf[3] = (cp << 5) | (filter << 3) | band;
if (i2c_transfer(&ttusb->i2c_adap, &tuner_msg, 1) != 1) return -EIO;
msleep(1);
return 0;
}
static int philips_tdm1316l_request_firmware(struct dvb_frontend* fe, const struct firmware **fw, char* name)
{
struct ttusb* ttusb = (struct ttusb*) fe->dvb->priv;
return request_firmware(fw, name, &ttusb->dev->dev);
}
struct tda1004x_config philips_tdm1316l_config = {
.demod_address = 0x8,
.invert = 1,
.pll_init = philips_tdm1316l_pll_init,
.pll_set = philips_tdm1316l_pll_set,
.request_firmware = philips_tdm1316l_request_firmware,
};
static void frontend_init(struct ttusb* ttusb)
{
switch(ttusb->dev->descriptor.idProduct) {
case 0x1005: // Hauppauge/TT Nova-USB-t budget (tda10046/Philips td1316(tda6651tt) OR cx22700/ALPS TDMB7(??))
// try the ALPS TDMB7 first
ttusb->fe = cx22700_attach(&alps_tdmb7_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) break;
// Philips td1316
ttusb->fe = tda10046_attach(&philips_tdm1316l_config, &ttusb->i2c_adap);
if (ttusb->fe != NULL) break;
break;
}
if (ttusb->fe == NULL) {
printk("dvb-ttusb-budget: A frontend driver was not found for device %04x/%04x\n",
ttusb->dev->descriptor.idVendor,
ttusb->dev->descriptor.idProduct);
} else {
if (dvb_register_frontend(ttusb->adapter, ttusb->fe)) {
printk("dvb-ttusb-budget: Frontend registration failed!\n");
if (ttusb->fe->ops->release)
ttusb->fe->ops->release(ttusb->fe);
ttusb->fe = NULL;
}
}
}
static struct i2c_algorithm ttusb_dec_algo = {
.name = "ttusb dec i2c algorithm",
.id = I2C_ALGO_BIT,
.master_xfer = master_xfer,
.functionality = functionality,
};
static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
struct usb_device *udev;
......@@ -1140,6 +1275,7 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
up(&ttusb->sem);
dvb_register_adapter(&ttusb->adapter, "Technotrend/Hauppauge Nova-USB", THIS_MODULE);
ttusb->adapter->priv = ttusb;
/* i2c */
memset(&ttusb->i2c_adap, 0, sizeof(struct i2c_adapter));
......@@ -1155,8 +1291,6 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
ttusb->i2c_adap.algo = &ttusb_dec_algo;
ttusb->i2c_adap.algo_data = NULL;
ttusb->i2c_adap.id = I2C_ALGO_BIT;
ttusb->i2c_adap.client_register = client_register;
ttusb->i2c_adap.client_unregister = client_unregister;
result = i2c_add_adapter(&ttusb->i2c_adap);
if (result) {
......@@ -1164,9 +1298,6 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
return result;
}
dvb_add_frontend_ioctls(ttusb->adapter, ttusb_lnb_ioctl, NULL,
ttusb);
memset(&ttusb->dvb_demux, 0, sizeof(ttusb->dvb_demux));
ttusb->dvb_demux.dmx.capabilities =
......@@ -1218,9 +1349,10 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP
| S_IROTH | S_IWOTH, &stc_fops, ttusb);
#endif
usb_set_intfdata(intf, (void *) ttusb);
frontend_init(ttusb);
return 0;
}
......@@ -1238,7 +1370,7 @@ static void ttusb_disconnect(struct usb_interface *intf)
dvb_net_release(&ttusb->dvbnet);
dvb_dmxdev_release(&ttusb->dmxdev);
dvb_dmx_release(&ttusb->dvb_demux);
if (ttusb->fe != NULL) dvb_unregister_frontend(ttusb->fe);
i2c_del_adapter(&ttusb->i2c_adap);
dvb_unregister_adapter(ttusb->adapter);
......@@ -1250,8 +1382,8 @@ static void ttusb_disconnect(struct usb_interface *intf)
}
static struct usb_device_id ttusb_table[] = {
{USB_DEVICE(0xb48, 0x1003)},
{USB_DEVICE(0xb48, 0x1004)}, /* to be confirmed ???? */
/* {USB_DEVICE(0xb48, 0x1003)},UNDEFINED HARDWARE - mail linuxtv.org list */
/* {USB_DEVICE(0xb48, 0x1004)},UNDEFINED HARDWARE - mail linuxtv.org list*/ /* to be confirmed ???? */
{USB_DEVICE(0xb48, 0x1005)},
{}
};
......
#include <asm/types.h>
u8 dsp_bootcode [] = {
static u8 dsp_bootcode [] = {
0x08, 0xaa, 0x00, 0x18, 0x00, 0x03, 0x08, 0x00,
0x00, 0x10, 0x00, 0x00, 0x01, 0x80, 0x18, 0x5f,
0x00, 0x00, 0x01, 0x80, 0x77, 0x18, 0x2a, 0xeb,
......
......@@ -30,11 +30,7 @@
#include <linux/version.h>
#include <linux/interrupt.h>
#include <linux/firmware.h>
#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
#include <linux/crc32.h>
#else
#warning "CRC checking of firmware not available"
#endif
#include <linux/init.h>
#include "dmxdev.h"
......@@ -42,6 +38,7 @@
#include "dvb_filter.h"
#include "dvb_frontend.h"
#include "dvb_net.h"
#include "ttusbdecfe.h"
static int debug;
static int output_pva;
......@@ -69,9 +66,6 @@ MODULE_PARM_DESC(output_pva, "Output PVA from dvr device (default:off)");
#define MAX_PVA_LENGTH 6144
#define LOF_HI 10600000
#define LOF_LO 9750000
enum ttusb_dec_model {
TTUSB_DEC2000T,
TTUSB_DEC2540T,
......@@ -102,12 +96,9 @@ struct ttusb_dec {
struct dvb_demux demux;
struct dmx_frontend frontend;
struct dvb_net dvb_net;
struct dvb_frontend_info *frontend_info;
int (*frontend_ioctl) (struct dvb_frontend *, unsigned int, void *);
struct dvb_frontend* fe;
u16 pid[DMX_PES_OTHER];
int hi_band;
int voltage;
/* USB bits */
struct usb_device *udev;
......@@ -166,32 +157,6 @@ struct filter_info {
struct list_head filter_info_list;
};
static struct dvb_frontend_info dec2000t_frontend_info = {
.name = "TechnoTrend/Hauppauge DEC2000-t Frontend",
.type = FE_OFDM,
.frequency_min = 51000000,
.frequency_max = 858000000,
.frequency_stepsize = 62500,
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO,
};
static struct dvb_frontend_info dec3000s_frontend_info = {
.name = "TechnoTrend/Hauppauge DEC3000-s Frontend",
.type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
.frequency_stepsize = 125,
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
FE_CAN_HIERARCHY_AUTO,
};
static void ttusb_dec_set_model(struct ttusb_dec *dec,
enum ttusb_dec_model model);
......@@ -1170,10 +1135,9 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
u16 firmware_csum = 0;
u16 firmware_csum_ns;
u32 firmware_size_nl;
#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
u32 crc32_csum, crc32_check, tmp;
#endif
const struct firmware *fw_entry = NULL;
dprintk("%s\n", __FUNCTION__);
if (request_firmware(&fw_entry, dec->firmware_name, &dec->udev->dev)) {
......@@ -1194,7 +1158,6 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
/* a 32 bit checksum over the first 56 bytes of the DSP Code is stored
at offset 56 of file, so use it to check if the firmware file is
valid. */
#if defined(CONFIG_CRC32) || defined(CONFIG_CRC32_MODULE)
crc32_csum = crc32(~0L, firmware, 56) ^ ~0L;
memcpy(&tmp, &firmware[56], 4);
crc32_check = htonl(tmp);
......@@ -1204,7 +1167,6 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec)
__FUNCTION__, crc32_csum, crc32_check);
return -1;
}
#endif
memcpy(idstring, &firmware[36], 20);
idstring[20] = '\0';
printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring);
......@@ -1404,6 +1366,7 @@ static void ttusb_dec_exit_dvb(struct ttusb_dec *dec)
dec->demux.dmx.remove_frontend(&dec->demux.dmx, &dec->frontend);
dvb_dmxdev_release(&dec->dmxdev);
dvb_dmx_release(&dec->demux);
if (dec->fe) dvb_unregister_frontend(dec->fe);
dvb_unregister_adapter(dec->adapter);
}
......@@ -1435,264 +1398,6 @@ static void ttusb_dec_exit_tasklet(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)
{
INIT_LIST_HEAD(&dec->filter_info_list);
......@@ -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,
const struct usb_device_id *id)
{
......@@ -1752,7 +1469,32 @@ static int ttusb_dec_probe(struct usb_interface *intf,
return 0;
}
ttusb_dec_init_dvb(dec);
ttusb_dec_init_frontend(dec);
dec->adapter->priv = dec;
switch (id->idProduct) {
case 0x1006:
dec->fe = ttusbdecfe_dvbs_attach(&fe_config);
break;
case 0x1008:
case 0x1009:
dec->fe = ttusbdecfe_dvbt_attach(&fe_config);
break;
}
if (dec->fe == NULL) {
printk("dvb-ttusb-dec: A frontend driver was not found for device %04x/%04x\n",
dec->udev->descriptor.idVendor,
dec->udev->descriptor.idProduct);
} else {
if (dvb_register_frontend(dec->adapter, dec->fe)) {
printk("budget-ci: Frontend registration failed!\n");
if (dec->fe->ops->release)
dec->fe->ops->release(dec->fe);
dec->fe = NULL;
}
}
ttusb_dec_init_v_pes(dec);
ttusb_dec_init_filters(dec);
ttusb_dec_init_tasklet(dec);
......@@ -1776,7 +1518,6 @@ static void ttusb_dec_disconnect(struct usb_interface *intf)
ttusb_dec_exit_tasklet(dec);
ttusb_dec_exit_filters(dec);
ttusb_dec_exit_usb(dec);
ttusb_dec_exit_frontend(dec);
ttusb_dec_exit_dvb(dec);
}
......@@ -1792,22 +1533,16 @@ static void ttusb_dec_set_model(struct ttusb_dec *dec,
case TTUSB_DEC2000T:
dec->model_name = "DEC2000-t";
dec->firmware_name = "dvb-ttusb-dec-2000t.fw";
dec->frontend_info = &dec2000t_frontend_info;
dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
break;
case TTUSB_DEC2540T:
dec->model_name = "DEC2540-t";
dec->firmware_name = "dvb-ttusb-dec-2540t.fw";
dec->frontend_info = &dec2000t_frontend_info;
dec->frontend_ioctl = ttusb_dec_2000t_frontend_ioctl;
break;
case TTUSB_DEC3000S:
dec->model_name = "DEC3000-s";
dec->firmware_name = "dvb-ttusb-dec-3000s.fw";
dec->frontend_info = &dec3000s_frontend_info;
dec->frontend_ioctl = ttusb_dec_3000s_frontend_ioctl;
break;
}
}
......
/*
* 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