Initial commit

This commit is contained in:
Ole André Vadla Ravnås 2022-05-07 01:01:45 +02:00
commit 169c65d57e
51358 changed files with 23120455 additions and 0 deletions

View file

@ -0,0 +1,23 @@
config DVB_B2C2_FLEXCOP
tristate
depends on DVB_CORE && I2C
depends on DVB_B2C2_FLEXCOP_PCI || DVB_B2C2_FLEXCOP_USB
default y
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0299 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MT312 if MEDIA_SUBDRV_AUTOSELECT
select DVB_NXT200X if MEDIA_SUBDRV_AUTOSELECT
select DVB_STV0297 if MEDIA_SUBDRV_AUTOSELECT
select DVB_BCM3510 if MEDIA_SUBDRV_AUTOSELECT
select DVB_LGDT330X if MEDIA_SUBDRV_AUTOSELECT
select DVB_S5H1420 if MEDIA_SUBDRV_AUTOSELECT
select DVB_TUNER_ITD1000 if MEDIA_SUBDRV_AUTOSELECT
select DVB_ISL6421 if MEDIA_SUBDRV_AUTOSELECT
select DVB_CX24123 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_SIMPLE if MEDIA_SUBDRV_AUTOSELECT
select DVB_TUNER_CX24113 if MEDIA_SUBDRV_AUTOSELECT
# Selected via the PCI or USB flexcop drivers
config DVB_B2C2_FLEXCOP_DEBUG
bool

View file

@ -0,0 +1,8 @@
b2c2-flexcop-objs += flexcop.o flexcop-fe-tuner.o flexcop-i2c.o
b2c2-flexcop-objs += flexcop-sram.o flexcop-eeprom.o flexcop-misc.o
b2c2-flexcop-objs += flexcop-hw-filter.o
obj-$(CONFIG_DVB_B2C2_FLEXCOP) += b2c2-flexcop.o
ccflags-y += -Idrivers/media/dvb-core/
ccflags-y += -Idrivers/media/dvb-frontends/
ccflags-y += -Idrivers/media/tuners/

View file

@ -0,0 +1,185 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop-common.h - common header file for device-specific source files
* see flexcop.c for copyright information
*/
#ifndef __FLEXCOP_COMMON_H__
#define __FLEXCOP_COMMON_H__
#include <linux/interrupt.h>
#include <linux/pci.h>
#include <linux/mutex.h>
#include "flexcop-reg.h"
#include "dmxdev.h"
#include "dvb_demux.h"
#include "dvb_filter.h"
#include "dvb_net.h"
#include "dvb_frontend.h"
#define FC_MAX_FEED 256
#ifndef FC_LOG_PREFIX
#warning please define a log prefix for your file, using a default one
#define FC_LOG_PREFIX "b2c2-undef"
#endif
/* Steal from usb.h */
#undef err
#define err(format, arg...) \
printk(KERN_ERR FC_LOG_PREFIX ": " format "\n" , ## arg)
#undef info
#define info(format, arg...) \
printk(KERN_INFO FC_LOG_PREFIX ": " format "\n" , ## arg)
#undef warn
#define warn(format, arg...) \
printk(KERN_WARNING FC_LOG_PREFIX ": " format "\n" , ## arg)
struct flexcop_dma {
struct pci_dev *pdev;
u8 *cpu_addr0;
dma_addr_t dma_addr0;
u8 *cpu_addr1;
dma_addr_t dma_addr1;
u32 size; /* size of each address in bytes */
};
struct flexcop_i2c_adapter {
struct flexcop_device *fc;
struct i2c_adapter i2c_adap;
u8 no_base_addr;
flexcop_i2c_port_t port;
};
/* Control structure for data definitions that are common to
* the B2C2-based PCI and USB devices.
*/
struct flexcop_device {
/* general */
struct device *dev; /* for firmware_class */
#define FC_STATE_DVB_INIT 0x01
#define FC_STATE_I2C_INIT 0x02
#define FC_STATE_FE_INIT 0x04
int init_state;
/* device information */
int has_32_hw_pid_filter;
flexcop_revision_t rev;
flexcop_device_type_t dev_type;
flexcop_bus_t bus_type;
/* dvb stuff */
struct dvb_adapter dvb_adapter;
struct dvb_frontend *fe;
struct dvb_net dvbnet;
struct dvb_demux demux;
struct dmxdev dmxdev;
struct dmx_frontend hw_frontend;
struct dmx_frontend mem_frontend;
int (*fe_sleep) (struct dvb_frontend *);
struct flexcop_i2c_adapter fc_i2c_adap[3];
struct mutex i2c_mutex;
struct module *owner;
/* options and status */
int extra_feedcount;
int feedcount;
int pid_filtering;
int fullts_streaming_state;
/* bus specific callbacks */
flexcop_ibi_value(*read_ibi_reg) (struct flexcop_device *,
flexcop_ibi_register);
int (*write_ibi_reg) (struct flexcop_device *,
flexcop_ibi_register, flexcop_ibi_value);
int (*i2c_request) (struct flexcop_i2c_adapter *,
flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
int (*stream_control) (struct flexcop_device *, int);
int (*get_mac_addr) (struct flexcop_device *fc, int extended);
void *bus_specific;
};
/* exported prototypes */
/* from flexcop.c */
void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len);
void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no);
struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len);
void flexcop_device_kfree(struct flexcop_device *);
int flexcop_device_initialize(struct flexcop_device *);
void flexcop_device_exit(struct flexcop_device *fc);
void flexcop_reset_block_300(struct flexcop_device *fc);
/* from flexcop-dma.c */
int flexcop_dma_allocate(struct pci_dev *pdev,
struct flexcop_dma *dma, u32 size);
void flexcop_dma_free(struct flexcop_dma *dma);
int flexcop_dma_control_timer_irq(struct flexcop_device *fc,
flexcop_dma_index_t no, int onoff);
int flexcop_dma_control_size_irq(struct flexcop_device *fc,
flexcop_dma_index_t no, int onoff);
int flexcop_dma_config(struct flexcop_device *fc, struct flexcop_dma *dma,
flexcop_dma_index_t dma_idx);
int flexcop_dma_xfer_control(struct flexcop_device *fc,
flexcop_dma_index_t dma_idx, flexcop_dma_addr_index_t index,
int onoff);
int flexcop_dma_config_timer(struct flexcop_device *fc,
flexcop_dma_index_t dma_idx, u8 cycles);
/* from flexcop-eeprom.c */
/* the PCI part uses this call to get the MAC address, the USB part has its own */
int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended);
/* from flexcop-i2c.c */
/* the PCI part uses this a i2c_request callback, whereas the usb part has its own
* one. We have it in flexcop-i2c.c, because it is going via the actual
* I2C-channel of the flexcop.
*/
int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t,
u8 chipaddr, u8 addr, u8 *buf, u16 len);
/* from flexcop-sram.c */
int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
flexcop_sram_dest_target_t target);
void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s);
void flexcop_sram_ctrl(struct flexcop_device *fc,
int usb_wan, int sramdma, int maximumfill);
/* global prototypes for the flexcop-chip */
/* from flexcop-fe-tuner.c */
int flexcop_frontend_init(struct flexcop_device *fc);
void flexcop_frontend_exit(struct flexcop_device *fc);
/* from flexcop-i2c.c */
int flexcop_i2c_init(struct flexcop_device *fc);
void flexcop_i2c_exit(struct flexcop_device *fc);
/* from flexcop-sram.c */
int flexcop_sram_init(struct flexcop_device *fc);
/* from flexcop-misc.c */
void flexcop_determine_revision(struct flexcop_device *fc);
void flexcop_device_name(struct flexcop_device *fc,
const char *prefix, const char *suffix);
void flexcop_dump_reg(struct flexcop_device *fc,
flexcop_ibi_register reg, int num);
/* from flexcop-hw-filter.c */
int flexcop_pid_feed_control(struct flexcop_device *fc,
struct dvb_demux_feed *dvbdmxfeed, int onoff);
void flexcop_hw_filter_init(struct flexcop_device *fc);
void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff);
void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6]);
void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff);
#endif

View file

@ -0,0 +1,147 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop-eeprom.c - eeprom access methods (currently only MAC address reading)
* see flexcop.c for copyright information
*/
#include "flexcop.h"
#if 0
/*EEPROM (Skystar2 has one "24LC08B" chip on board) */
static int eeprom_write(struct adapter *adapter, u16 addr, u8 *buf, u16 len)
{
return flex_i2c_write(adapter, 0x20000000, 0x50, addr, buf, len);
}
static int eeprom_lrc_write(struct adapter *adapter, u32 addr,
u32 len, u8 *wbuf, u8 *rbuf, int retries)
{
int i;
for (i = 0; i < retries; i++) {
if (eeprom_write(adapter, addr, wbuf, len) == len) {
if (eeprom_lrc_read(adapter, addr, len, rbuf, retries) == 1)
return 1;
}
}
return 0;
}
/* These functions could be used to unlock SkyStar2 cards. */
static int eeprom_writeKey(struct adapter *adapter, u8 *key, u32 len)
{
u8 rbuf[20];
u8 wbuf[20];
if (len != 16)
return 0;
memcpy(wbuf, key, len);
wbuf[16] = 0;
wbuf[17] = 0;
wbuf[18] = 0;
wbuf[19] = calc_lrc(wbuf, 19);
return eeprom_lrc_write(adapter, 0x3e4, 20, wbuf, rbuf, 4);
}
static int eeprom_readKey(struct adapter *adapter, u8 *key, u32 len)
{
u8 buf[20];
if (len != 16)
return 0;
if (eeprom_lrc_read(adapter, 0x3e4, 20, buf, 4) == 0)
return 0;
memcpy(key, buf, len);
return 1;
}
static char eeprom_set_mac_addr(struct adapter *adapter, char type, u8 *mac)
{
u8 tmp[8];
if (type != 0) {
tmp[0] = mac[0];
tmp[1] = mac[1];
tmp[2] = mac[2];
tmp[3] = mac[5];
tmp[4] = mac[6];
tmp[5] = mac[7];
} else {
tmp[0] = mac[0];
tmp[1] = mac[1];
tmp[2] = mac[2];
tmp[3] = mac[3];
tmp[4] = mac[4];
tmp[5] = mac[5];
}
tmp[6] = 0;
tmp[7] = calc_lrc(tmp, 7);
if (eeprom_write(adapter, 0x3f8, tmp, 8) == 8)
return 1;
return 0;
}
static int flexcop_eeprom_read(struct flexcop_device *fc,
u16 addr, u8 *buf, u16 len)
{
return fc->i2c_request(fc,FC_READ,FC_I2C_PORT_EEPROM,0x50,addr,buf,len);
}
#endif
static u8 calc_lrc(u8 *buf, int len)
{
int i;
u8 sum = 0;
for (i = 0; i < len; i++)
sum = sum ^ buf[i];
return sum;
}
static int flexcop_eeprom_request(struct flexcop_device *fc,
flexcop_access_op_t op, u16 addr, u8 *buf, u16 len, int retries)
{
int i,ret = 0;
u8 chipaddr = 0x50 | ((addr >> 8) & 3);
for (i = 0; i < retries; i++) {
ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr,
addr & 0xff, buf, len);
if (ret == 0)
break;
}
return ret;
}
static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr,
u8 *buf, u16 len, int retries)
{
int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries);
if (ret == 0)
if (calc_lrc(buf, len - 1) != buf[len - 1])
ret = -EINVAL;
return ret;
}
/* JJ's comment about extended == 1: it is not presently used anywhere but was
* added to the low-level functions for possible support of EUI64 */
int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended)
{
u8 buf[8];
int ret = 0;
if ((ret = flexcop_eeprom_lrc_read(fc,0x3f8,buf,8,4)) == 0) {
if (extended != 0) {
err("TODO: extended (EUI64) MAC addresses aren't "
"completely supported yet");
ret = -EINVAL;
} else
memcpy(fc->dvb_adapter.proposed_mac,buf,6);
}
return ret;
}
EXPORT_SYMBOL(flexcop_eeprom_check_mac_addr);

View file

@ -0,0 +1,678 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop-fe-tuner.c - methods for frontend attachment and DiSEqC controlling
* see flexcop.c for copyright information
*/
#include <media/tuner.h>
#include "flexcop.h"
#include "mt312.h"
#include "stv0299.h"
#include "s5h1420.h"
#include "itd1000.h"
#include "cx24113.h"
#include "cx24123.h"
#include "isl6421.h"
#include "mt352.h"
#include "bcm3510.h"
#include "nxt200x.h"
#include "dvb-pll.h"
#include "lgdt330x.h"
#include "tuner-simple.h"
#include "stv0297.h"
/* Can we use the specified front-end? Remember that if we are compiled
* into the kernel we can't call code that's in modules. */
#define FE_SUPPORTED(fe) (defined(CONFIG_DVB_##fe) || \
(defined(CONFIG_DVB_##fe##_MODULE) && defined(MODULE)))
/* lnb control */
#if FE_SUPPORTED(MT312) || FE_SUPPORTED(STV0299)
static int flexcop_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
{
struct flexcop_device *fc = fe->dvb->priv;
flexcop_ibi_value v;
deb_tuner("polarity/voltage = %u\n", voltage);
v = fc->read_ibi_reg(fc, misc_204);
switch (voltage) {
case SEC_VOLTAGE_OFF:
v.misc_204.ACPI1_sig = 1;
break;
case SEC_VOLTAGE_13:
v.misc_204.ACPI1_sig = 0;
v.misc_204.LNB_L_H_sig = 0;
break;
case SEC_VOLTAGE_18:
v.misc_204.ACPI1_sig = 0;
v.misc_204.LNB_L_H_sig = 1;
break;
default:
err("unknown SEC_VOLTAGE value");
return -EINVAL;
}
return fc->write_ibi_reg(fc, misc_204, v);
}
#endif
#if FE_SUPPORTED(S5H1420) || FE_SUPPORTED(STV0299) || FE_SUPPORTED(MT312)
static int flexcop_sleep(struct dvb_frontend* fe)
{
struct flexcop_device *fc = fe->dvb->priv;
if (fc->fe_sleep)
return fc->fe_sleep(fe);
return 0;
}
#endif
/* SkyStar2 DVB-S rev 2.3 */
#if FE_SUPPORTED(MT312) && FE_SUPPORTED(PLL)
static int flexcop_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
{
/* u16 wz_half_period_for_45_mhz[] = { 0x01ff, 0x0154, 0x00ff, 0x00cc }; */
struct flexcop_device *fc = fe->dvb->priv;
flexcop_ibi_value v;
u16 ax;
v.raw = 0;
deb_tuner("tone = %u\n",tone);
switch (tone) {
case SEC_TONE_ON:
ax = 0x01ff;
break;
case SEC_TONE_OFF:
ax = 0;
break;
default:
err("unknown SEC_TONE value");
return -EINVAL;
}
v.lnb_switch_freq_200.LNB_CTLPrescaler_sig = 1; /* divide by 2 */
v.lnb_switch_freq_200.LNB_CTLHighCount_sig = ax;
v.lnb_switch_freq_200.LNB_CTLLowCount_sig = ax == 0 ? 0x1ff : ax;
return fc->write_ibi_reg(fc,lnb_switch_freq_200,v);
}
static void flexcop_diseqc_send_bit(struct dvb_frontend* fe, int data)
{
flexcop_set_tone(fe, SEC_TONE_ON);
udelay(data ? 500 : 1000);
flexcop_set_tone(fe, SEC_TONE_OFF);
udelay(data ? 1000 : 500);
}
static void flexcop_diseqc_send_byte(struct dvb_frontend* fe, int data)
{
int i, par = 1, d;
for (i = 7; i >= 0; i--) {
d = (data >> i) & 1;
par ^= d;
flexcop_diseqc_send_bit(fe, d);
}
flexcop_diseqc_send_bit(fe, par);
}
static int flexcop_send_diseqc_msg(struct dvb_frontend *fe,
int len, u8 *msg, unsigned long burst)
{
int i;
flexcop_set_tone(fe, SEC_TONE_OFF);
mdelay(16);
for (i = 0; i < len; i++)
flexcop_diseqc_send_byte(fe,msg[i]);
mdelay(16);
if (burst != -1) {
if (burst)
flexcop_diseqc_send_byte(fe, 0xff);
else {
flexcop_set_tone(fe, SEC_TONE_ON);
mdelay(12);
udelay(500);
flexcop_set_tone(fe, SEC_TONE_OFF);
}
msleep(20);
}
return 0;
}
static int flexcop_diseqc_send_master_cmd(struct dvb_frontend *fe,
struct dvb_diseqc_master_cmd *cmd)
{
return flexcop_send_diseqc_msg(fe, cmd->msg_len, cmd->msg, 0);
}
static int flexcop_diseqc_send_burst(struct dvb_frontend *fe,
fe_sec_mini_cmd_t minicmd)
{
return flexcop_send_diseqc_msg(fe, 0, NULL, minicmd);
}
static struct mt312_config skystar23_samsung_tbdu18132_config = {
.demod_address = 0x0e,
};
static int skystar2_rev23_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
struct dvb_frontend_ops *ops;
fc->fe = dvb_attach(mt312_attach, &skystar23_samsung_tbdu18132_config, i2c);
if (!fc->fe)
return 0;
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
DVB_PLL_SAMSUNG_TBDU18132))
return 0;
ops = &fc->fe->ops;
ops->diseqc_send_master_cmd = flexcop_diseqc_send_master_cmd;
ops->diseqc_send_burst = flexcop_diseqc_send_burst;
ops->set_tone = flexcop_set_tone;
ops->set_voltage = flexcop_set_voltage;
fc->fe_sleep = ops->sleep;
ops->sleep = flexcop_sleep;
return 1;
}
#else
#define skystar2_rev23_attach NULL
#endif
/* SkyStar2 DVB-S rev 2.6 */
#if FE_SUPPORTED(STV0299) && FE_SUPPORTED(PLL)
static int samsung_tbmu24112_set_symbol_rate(struct dvb_frontend *fe,
u32 srate, u32 ratio)
{
u8 aclk = 0;
u8 bclk = 0;
if (srate < 1500000) {
aclk = 0xb7; bclk = 0x47;
} else if (srate < 3000000) {
aclk = 0xb7; bclk = 0x4b;
} else if (srate < 7000000) {
aclk = 0xb7; bclk = 0x4f;
} else if (srate < 14000000) {
aclk = 0xb7; bclk = 0x53;
} else if (srate < 30000000) {
aclk = 0xb6; bclk = 0x53;
} else if (srate < 45000000) {
aclk = 0xb4; bclk = 0x51;
}
stv0299_writereg(fe, 0x13, aclk);
stv0299_writereg(fe, 0x14, bclk);
stv0299_writereg(fe, 0x1f, (ratio >> 16) & 0xff);
stv0299_writereg(fe, 0x20, (ratio >> 8) & 0xff);
stv0299_writereg(fe, 0x21, ratio & 0xf0);
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,
.skip_reinit = 0,
.lock_output = STV0299_LOCKOUTPUT_LK,
.volt13_op0_op1 = STV0299_VOLT13_OP1,
.min_delay_ms = 100,
.set_symbol_rate = samsung_tbmu24112_set_symbol_rate,
};
static int skystar2_rev26_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
if (!fc->fe)
return 0;
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61, i2c,
DVB_PLL_SAMSUNG_TBMU24112))
return 0;
fc->fe->ops.set_voltage = flexcop_set_voltage;
fc->fe_sleep = fc->fe->ops.sleep;
fc->fe->ops.sleep = flexcop_sleep;
return 1;
}
#else
#define skystar2_rev26_attach NULL
#endif
/* SkyStar2 DVB-S rev 2.7 */
#if FE_SUPPORTED(S5H1420) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_ITD1000)
static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
.demod_address = 0x53,
.invert = 1,
.repeated_start_workaround = 1,
.serial_mpeg = 1,
};
static struct itd1000_config skystar2_rev2_7_itd1000_config = {
.i2c_address = 0x61,
};
static int skystar2_rev27_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
flexcop_ibi_value r108;
struct i2c_adapter *i2c_tuner;
/* enable no_base_addr - no repeated start when reading */
fc->fc_i2c_adap[0].no_base_addr = 1;
fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config,
i2c);
if (!fc->fe)
goto fail;
i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
if (!i2c_tuner)
goto fail;
fc->fe_sleep = fc->fe->ops.sleep;
fc->fe->ops.sleep = flexcop_sleep;
/* enable no_base_addr - no repeated start when reading */
fc->fc_i2c_adap[2].no_base_addr = 1;
if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
0x08, 1, 1, false)) {
err("ISL6421 could NOT be attached");
goto fail_isl;
}
info("ISL6421 successfully attached");
/* the ITD1000 requires a lower i2c clock - is it a problem ? */
r108.raw = 0x00000506;
fc->write_ibi_reg(fc, tw_sm_c_108, r108);
if (!dvb_attach(itd1000_attach, fc->fe, i2c_tuner,
&skystar2_rev2_7_itd1000_config)) {
err("ITD1000 could NOT be attached");
/* Should i2c clock be restored? */
goto fail_isl;
}
info("ITD1000 successfully attached");
return 1;
fail_isl:
fc->fc_i2c_adap[2].no_base_addr = 0;
fail:
/* for the next devices we need it again */
fc->fc_i2c_adap[0].no_base_addr = 0;
return 0;
}
#else
#define skystar2_rev27_attach NULL
#endif
/* SkyStar2 rev 2.8 */
#if FE_SUPPORTED(CX24123) && FE_SUPPORTED(ISL6421) && FE_SUPPORTED(TUNER_CX24113)
static struct cx24123_config skystar2_rev2_8_cx24123_config = {
.demod_address = 0x55,
.dont_use_pll = 1,
.agc_callback = cx24113_agc_callback,
};
static const struct cx24113_config skystar2_rev2_8_cx24113_config = {
.i2c_addr = 0x54,
.xtal_khz = 10111,
};
static int skystar2_rev28_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
struct i2c_adapter *i2c_tuner;
fc->fe = dvb_attach(cx24123_attach, &skystar2_rev2_8_cx24123_config,
i2c);
if (!fc->fe)
return 0;
i2c_tuner = cx24123_get_tuner_i2c_adapter(fc->fe);
if (!i2c_tuner)
return 0;
if (!dvb_attach(cx24113_attach, fc->fe, &skystar2_rev2_8_cx24113_config,
i2c_tuner)) {
err("CX24113 could NOT be attached");
return 0;
}
info("CX24113 successfully attached");
fc->fc_i2c_adap[2].no_base_addr = 1;
if (!dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap,
0x08, 0, 0, false)) {
err("ISL6421 could NOT be attached");
fc->fc_i2c_adap[2].no_base_addr = 0;
return 0;
}
info("ISL6421 successfully attached");
/* TODO on i2c_adap[1] addr 0x11 (EEPROM) there seems to be an
* IR-receiver (PIC16F818) - but the card has no input for that ??? */
return 1;
}
#else
#define skystar2_rev28_attach NULL
#endif
/* AirStar DVB-T */
#if FE_SUPPORTED(MT352) && FE_SUPPORTED(PLL)
static int samsung_tdtc9251dh0_demod_init(struct dvb_frontend *fe)
{
static u8 mt352_clock_config[] = { 0x89, 0x18, 0x2d };
static u8 mt352_reset[] = { 0x50, 0x80 };
static u8 mt352_adc_ctl_1_cfg[] = { 0x8E, 0x40 };
static u8 mt352_agc_cfg[] = { 0x67, 0x28, 0xa1 };
static u8 mt352_capt_range_cfg[] = { 0x75, 0x32 };
mt352_write(fe, mt352_clock_config, sizeof(mt352_clock_config));
udelay(2000);
mt352_write(fe, mt352_reset, sizeof(mt352_reset));
mt352_write(fe, mt352_adc_ctl_1_cfg, sizeof(mt352_adc_ctl_1_cfg));
mt352_write(fe, mt352_agc_cfg, sizeof(mt352_agc_cfg));
mt352_write(fe, mt352_capt_range_cfg, sizeof(mt352_capt_range_cfg));
return 0;
}
static struct mt352_config samsung_tdtc9251dh0_config = {
.demod_address = 0x0f,
.demod_init = samsung_tdtc9251dh0_demod_init,
};
static int airstar_dvbt_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
if (!fc->fe)
return 0;
return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
DVB_PLL_SAMSUNG_TDTC9251DH0);
}
#else
#define airstar_dvbt_attach NULL
#endif
/* AirStar ATSC 1st generation */
#if FE_SUPPORTED(BCM3510)
static int flexcop_fe_request_firmware(struct dvb_frontend *fe,
const struct firmware **fw, char* name)
{
struct flexcop_device *fc = fe->dvb->priv;
return request_firmware(fw, name, fc->dev);
}
static struct bcm3510_config air2pc_atsc_first_gen_config = {
.demod_address = 0x0f,
.request_firmware = flexcop_fe_request_firmware,
};
static int airstar_atsc1_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
return fc->fe != NULL;
}
#else
#define airstar_atsc1_attach NULL
#endif
/* AirStar ATSC 2nd generation */
#if FE_SUPPORTED(NXT200X) && FE_SUPPORTED(PLL)
static struct nxt200x_config samsung_tbmv_config = {
.demod_address = 0x0a,
};
static int airstar_atsc2_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
if (!fc->fe)
return 0;
return !!dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL,
DVB_PLL_SAMSUNG_TBMV);
}
#else
#define airstar_atsc2_attach NULL
#endif
/* AirStar ATSC 3rd generation */
#if FE_SUPPORTED(LGDT330X)
static struct lgdt330x_config air2pc_atsc_hd5000_config = {
.demod_address = 0x59,
.demod_chip = LGDT3303,
.serial_mpeg = 0x04,
.clock_polarity_flip = 1,
};
static int airstar_atsc3_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
if (!fc->fe)
return 0;
return !!dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
TUNER_LG_TDVS_H06XF);
}
#else
#define airstar_atsc3_attach NULL
#endif
/* CableStar2 DVB-C */
#if FE_SUPPORTED(STV0297) && FE_SUPPORTED(PLL)
static u8 alps_tdee4_stv0297_inittab[] = {
0x80, 0x01,
0x80, 0x00,
0x81, 0x01,
0x81, 0x00,
0x00, 0x48,
0x01, 0x58,
0x03, 0x00,
0x04, 0x00,
0x07, 0x00,
0x08, 0x00,
0x30, 0xff,
0x31, 0x9d,
0x32, 0xff,
0x33, 0x00,
0x34, 0x29,
0x35, 0x55,
0x36, 0x80,
0x37, 0x6e,
0x38, 0x9c,
0x40, 0x1a,
0x41, 0xfe,
0x42, 0x33,
0x43, 0x00,
0x44, 0xff,
0x45, 0x00,
0x46, 0x00,
0x49, 0x04,
0x4a, 0x51,
0x4b, 0xf8,
0x52, 0x30,
0x53, 0x06,
0x59, 0x06,
0x5a, 0x5e,
0x5b, 0x04,
0x61, 0x49,
0x62, 0x0a,
0x70, 0xff,
0x71, 0x04,
0x72, 0x00,
0x73, 0x00,
0x74, 0x0c,
0x80, 0x20,
0x81, 0x00,
0x82, 0x30,
0x83, 0x00,
0x84, 0x04,
0x85, 0x22,
0x86, 0x08,
0x87, 0x1b,
0x88, 0x00,
0x89, 0x00,
0x90, 0x00,
0x91, 0x04,
0xa0, 0x86,
0xa1, 0x00,
0xa2, 0x00,
0xb0, 0x91,
0xb1, 0x0b,
0xc0, 0x5b,
0xc1, 0x10,
0xc2, 0x12,
0xd0, 0x02,
0xd1, 0x00,
0xd2, 0x00,
0xd3, 0x00,
0xd4, 0x02,
0xd5, 0x00,
0xde, 0x00,
0xdf, 0x01,
0xff, 0xff,
};
static struct stv0297_config alps_tdee4_stv0297_config = {
.demod_address = 0x1c,
.inittab = alps_tdee4_stv0297_inittab,
};
static int cablestar2_attach(struct flexcop_device *fc,
struct i2c_adapter *i2c)
{
fc->fc_i2c_adap[0].no_base_addr = 1;
fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
if (!fc->fe)
goto fail;
/* This tuner doesn't use the stv0297's I2C gate, but instead the
* tuner is connected to a different flexcop I2C adapter. */
if (fc->fe->ops.i2c_gate_ctrl)
fc->fe->ops.i2c_gate_ctrl(fc->fe, 0);
fc->fe->ops.i2c_gate_ctrl = NULL;
if (!dvb_attach(dvb_pll_attach, fc->fe, 0x61,
&fc->fc_i2c_adap[2].i2c_adap, DVB_PLL_TDEE4))
goto fail;
return 1;
fail:
/* Reset for next frontend to try */
fc->fc_i2c_adap[0].no_base_addr = 0;
return 0;
}
#else
#define cablestar2_attach NULL
#endif
static struct {
flexcop_device_type_t type;
int (*attach)(struct flexcop_device *, struct i2c_adapter *);
} flexcop_frontends[] = {
{ FC_SKY_REV27, skystar2_rev27_attach },
{ FC_SKY_REV28, skystar2_rev28_attach },
{ FC_SKY_REV26, skystar2_rev26_attach },
{ FC_AIR_DVBT, airstar_dvbt_attach },
{ FC_AIR_ATSC2, airstar_atsc2_attach },
{ FC_AIR_ATSC3, airstar_atsc3_attach },
{ FC_AIR_ATSC1, airstar_atsc1_attach },
{ FC_CABLE, cablestar2_attach },
{ FC_SKY_REV23, skystar2_rev23_attach },
};
/* try to figure out the frontend */
int flexcop_frontend_init(struct flexcop_device *fc)
{
int i;
for (i = 0; i < ARRAY_SIZE(flexcop_frontends); i++) {
if (!flexcop_frontends[i].attach)
continue;
/* type needs to be set before, because of some workarounds
* done based on the probed card type */
fc->dev_type = flexcop_frontends[i].type;
if (flexcop_frontends[i].attach(fc, &fc->fc_i2c_adap[0].i2c_adap))
goto fe_found;
/* Clean up partially attached frontend */
if (fc->fe) {
dvb_frontend_detach(fc->fe);
fc->fe = NULL;
}
}
fc->dev_type = FC_UNK;
err("no frontend driver found for this B2C2/FlexCop adapter");
return -ENODEV;
fe_found:
info("found '%s' .", fc->fe->ops.info.name);
if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
err("frontend registration failed!");
dvb_frontend_detach(fc->fe);
fc->fe = NULL;
return -EINVAL;
}
fc->init_state |= FC_STATE_FE_INIT;
return 0;
}
void flexcop_frontend_exit(struct flexcop_device *fc)
{
if (fc->init_state & FC_STATE_FE_INIT) {
dvb_unregister_frontend(fc->fe);
dvb_frontend_detach(fc->fe);
}
fc->init_state &= ~FC_STATE_FE_INIT;
}

View file

@ -0,0 +1,232 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop-hw-filter.c - pid and mac address filtering and control functions
* see flexcop.c for copyright information
*/
#include "flexcop.h"
static void flexcop_rcv_data_ctrl(struct flexcop_device *fc, int onoff)
{
flexcop_set_ibi_value(ctrl_208, Rcv_Data_sig, onoff);
deb_ts("rcv_data is now: '%s'\n", onoff ? "on" : "off");
}
void flexcop_smc_ctrl(struct flexcop_device *fc, int onoff)
{
flexcop_set_ibi_value(ctrl_208, SMC_Enable_sig, onoff);
}
static void flexcop_null_filter_ctrl(struct flexcop_device *fc, int onoff)
{
flexcop_set_ibi_value(ctrl_208, Null_filter_sig, onoff);
}
void flexcop_set_mac_filter(struct flexcop_device *fc, u8 mac[6])
{
flexcop_ibi_value v418, v41c;
v41c = fc->read_ibi_reg(fc, mac_address_41c);
v418.mac_address_418.MAC1 = mac[0];
v418.mac_address_418.MAC2 = mac[1];
v418.mac_address_418.MAC3 = mac[2];
v418.mac_address_418.MAC6 = mac[3];
v41c.mac_address_41c.MAC7 = mac[4];
v41c.mac_address_41c.MAC8 = mac[5];
fc->write_ibi_reg(fc, mac_address_418, v418);
fc->write_ibi_reg(fc, mac_address_41c, v41c);
}
void flexcop_mac_filter_ctrl(struct flexcop_device *fc, int onoff)
{
flexcop_set_ibi_value(ctrl_208, MAC_filter_Mode_sig, onoff);
}
static void flexcop_pid_group_filter(struct flexcop_device *fc,
u16 pid, u16 mask)
{
/* index_reg_310.extra_index_reg need to 0 or 7 to work */
flexcop_ibi_value v30c;
v30c.pid_filter_30c_ext_ind_0_7.Group_PID = pid;
v30c.pid_filter_30c_ext_ind_0_7.Group_mask = mask;
fc->write_ibi_reg(fc, pid_filter_30c, v30c);
}
static void flexcop_pid_group_filter_ctrl(struct flexcop_device *fc, int onoff)
{
flexcop_set_ibi_value(ctrl_208, Mask_filter_sig, onoff);
}
/* this fancy define reduces the code size of the quite similar PID controlling of
* the first 6 PIDs
*/
#define pid_ctrl(vregname,field,enablefield,trans_field,transval) \
flexcop_ibi_value vpid = fc->read_ibi_reg(fc, vregname), \
v208 = fc->read_ibi_reg(fc, ctrl_208); \
vpid.vregname.field = onoff ? pid : 0x1fff; \
vpid.vregname.trans_field = transval; \
v208.ctrl_208.enablefield = onoff; \
fc->write_ibi_reg(fc, vregname, vpid); \
fc->write_ibi_reg(fc, ctrl_208, v208);
static void flexcop_pid_Stream1_PID_ctrl(struct flexcop_device *fc,
u16 pid, int onoff)
{
pid_ctrl(pid_filter_300, Stream1_PID, Stream1_filter_sig,
Stream1_trans, 0);
}
static void flexcop_pid_Stream2_PID_ctrl(struct flexcop_device *fc,
u16 pid, int onoff)
{
pid_ctrl(pid_filter_300, Stream2_PID, Stream2_filter_sig,
Stream2_trans, 0);
}
static void flexcop_pid_PCR_PID_ctrl(struct flexcop_device *fc,
u16 pid, int onoff)
{
pid_ctrl(pid_filter_304, PCR_PID, PCR_filter_sig, PCR_trans, 0);
}
static void flexcop_pid_PMT_PID_ctrl(struct flexcop_device *fc,
u16 pid, int onoff)
{
pid_ctrl(pid_filter_304, PMT_PID, PMT_filter_sig, PMT_trans, 0);
}
static void flexcop_pid_EMM_PID_ctrl(struct flexcop_device *fc,
u16 pid, int onoff)
{
pid_ctrl(pid_filter_308, EMM_PID, EMM_filter_sig, EMM_trans, 0);
}
static void flexcop_pid_ECM_PID_ctrl(struct flexcop_device *fc,
u16 pid, int onoff)
{
pid_ctrl(pid_filter_308, ECM_PID, ECM_filter_sig, ECM_trans, 0);
}
static void flexcop_pid_control(struct flexcop_device *fc,
int index, u16 pid, int onoff)
{
if (pid == 0x2000)
return;
deb_ts("setting pid: %5d %04x at index %d '%s'\n",
pid, pid, index, onoff ? "on" : "off");
/* We could use bit magic here to reduce source code size.
* I decided against it, but to use the real register names */
switch (index) {
case 0:
flexcop_pid_Stream1_PID_ctrl(fc, pid, onoff);
break;
case 1:
flexcop_pid_Stream2_PID_ctrl(fc, pid, onoff);
break;
case 2:
flexcop_pid_PCR_PID_ctrl(fc, pid, onoff);
break;
case 3:
flexcop_pid_PMT_PID_ctrl(fc, pid, onoff);
break;
case 4:
flexcop_pid_EMM_PID_ctrl(fc, pid, onoff);
break;
case 5:
flexcop_pid_ECM_PID_ctrl(fc, pid, onoff);
break;
default:
if (fc->has_32_hw_pid_filter && index < 38) {
flexcop_ibi_value vpid, vid;
/* set the index */
vid = fc->read_ibi_reg(fc, index_reg_310);
vid.index_reg_310.index_reg = index - 6;
fc->write_ibi_reg(fc, index_reg_310, vid);
vpid = fc->read_ibi_reg(fc, pid_n_reg_314);
vpid.pid_n_reg_314.PID = onoff ? pid : 0x1fff;
vpid.pid_n_reg_314.PID_enable_bit = onoff;
fc->write_ibi_reg(fc, pid_n_reg_314, vpid);
}
break;
}
}
static int flexcop_toggle_fullts_streaming(struct flexcop_device *fc, int onoff)
{
if (fc->fullts_streaming_state != onoff) {
deb_ts("%s full TS transfer\n",onoff ? "enabling" : "disabling");
flexcop_pid_group_filter(fc, 0, 0x1fe0 * (!onoff));
flexcop_pid_group_filter_ctrl(fc, onoff);
fc->fullts_streaming_state = onoff;
}
return 0;
}
int flexcop_pid_feed_control(struct flexcop_device *fc,
struct dvb_demux_feed *dvbdmxfeed, int onoff)
{
int max_pid_filter = 6 + fc->has_32_hw_pid_filter*32;
fc->feedcount += onoff ? 1 : -1; /* the number of PIDs/Feed currently requested */
if (dvbdmxfeed->index >= max_pid_filter)
fc->extra_feedcount += onoff ? 1 : -1;
/* toggle complete-TS-streaming when:
* - pid_filtering is not enabled and it is the first or last feed requested
* - pid_filtering is enabled,
* - but the number of requested feeds is exceeded
* - or the requested pid is 0x2000 */
if (!fc->pid_filtering && fc->feedcount == onoff)
flexcop_toggle_fullts_streaming(fc, onoff);
if (fc->pid_filtering) {
flexcop_pid_control \
(fc, dvbdmxfeed->index, dvbdmxfeed->pid, onoff);
if (fc->extra_feedcount > 0)
flexcop_toggle_fullts_streaming(fc, 1);
else if (dvbdmxfeed->pid == 0x2000)
flexcop_toggle_fullts_streaming(fc, onoff);
else
flexcop_toggle_fullts_streaming(fc, 0);
}
/* if it was the first or last feed request change the stream-status */
if (fc->feedcount == onoff) {
flexcop_rcv_data_ctrl(fc, onoff);
if (fc->stream_control) /* device specific stream control */
fc->stream_control(fc, onoff);
/* feeding stopped -> reset the flexcop filter*/
if (onoff == 0) {
flexcop_reset_block_300(fc);
flexcop_hw_filter_init(fc);
}
}
return 0;
}
EXPORT_SYMBOL(flexcop_pid_feed_control);
void flexcop_hw_filter_init(struct flexcop_device *fc)
{
int i;
flexcop_ibi_value v;
for (i = 0; i < 6 + 32*fc->has_32_hw_pid_filter; i++)
flexcop_pid_control(fc, i, 0x1fff, 0);
flexcop_pid_group_filter(fc, 0, 0x1fe0);
flexcop_pid_group_filter_ctrl(fc, 0);
v = fc->read_ibi_reg(fc, pid_filter_308);
v.pid_filter_308.EMM_filter_4 = 1;
v.pid_filter_308.EMM_filter_6 = 0;
fc->write_ibi_reg(fc, pid_filter_308, v);
flexcop_null_filter_ctrl(fc, 1);
}

View file

@ -0,0 +1,288 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop-i2c.c - flexcop internal 2Wire bus (I2C) and dvb i2c initialization
* see flexcop.c for copyright information
*/
#include "flexcop.h"
#define FC_MAX_I2C_RETRIES 100000
static int flexcop_i2c_operation(struct flexcop_device *fc,
flexcop_ibi_value *r100)
{
int i;
flexcop_ibi_value r;
r100->tw_sm_c_100.working_start = 1;
deb_i2c("r100 before: %08x\n",r100->raw);
fc->write_ibi_reg(fc, tw_sm_c_100, ibi_zero);
fc->write_ibi_reg(fc, tw_sm_c_100, *r100); /* initiating i2c operation */
for (i = 0; i < FC_MAX_I2C_RETRIES; i++) {
r = fc->read_ibi_reg(fc, tw_sm_c_100);
if (!r.tw_sm_c_100.no_base_addr_ack_error) {
if (r.tw_sm_c_100.st_done) {
*r100 = r;
deb_i2c("i2c success\n");
return 0;
}
} else {
deb_i2c("suffering from an i2c ack_error\n");
return -EREMOTEIO;
}
}
deb_i2c("tried %d times i2c operation, "
"never finished or too many ack errors.\n", i);
return -EREMOTEIO;
}
static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
flexcop_ibi_value r100, u8 *buf)
{
flexcop_ibi_value r104;
int len = r100.tw_sm_c_100.total_bytes,
/* remember total_bytes is buflen-1 */
ret;
/* work-around to have CableStar2 and SkyStar2 rev 2.7 work
* correctly:
*
* the ITD1000 is behind an i2c-gate which closes automatically
* after an i2c-transaction the STV0297 needs 2 consecutive reads
* one with no_base_addr = 0 and one with 1
*
* those two work-arounds are conflictin: we check for the card
* type, it is set when probing the ITD1000 */
if (i2c->fc->dev_type == FC_SKY_REV27)
r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
ret = flexcop_i2c_operation(i2c->fc, &r100);
if (ret != 0) {
deb_i2c("Retrying operation\n");
r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
ret = flexcop_i2c_operation(i2c->fc, &r100);
}
if (ret != 0) {
deb_i2c("read failed. %d\n", ret);
return ret;
}
buf[0] = r100.tw_sm_c_100.data1_reg;
if (len > 0) {
r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104);
deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
/* there is at least one more byte, otherwise we wouldn't be here */
buf[1] = r104.tw_sm_c_104.data2_reg;
if (len > 1) buf[2] = r104.tw_sm_c_104.data3_reg;
if (len > 2) buf[3] = r104.tw_sm_c_104.data4_reg;
}
return 0;
}
static int flexcop_i2c_write4(struct flexcop_device *fc,
flexcop_ibi_value r100, u8 *buf)
{
flexcop_ibi_value r104;
int len = r100.tw_sm_c_100.total_bytes; /* remember total_bytes is buflen-1 */
r104.raw = 0;
/* there is at least one byte, otherwise we wouldn't be here */
r100.tw_sm_c_100.data1_reg = buf[0];
r104.tw_sm_c_104.data2_reg = len > 0 ? buf[1] : 0;
r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
/* write the additional i2c data before doing the actual i2c operation */
fc->write_ibi_reg(fc, tw_sm_c_104, r104);
return flexcop_i2c_operation(fc, &r100);
}
int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
{
int ret;
#ifdef DUMP_I2C_MESSAGES
int i;
#endif
u16 bytes_to_transfer;
flexcop_ibi_value r100;
deb_i2c("op = %d\n",op);
r100.raw = 0;
r100.tw_sm_c_100.chipaddr = chipaddr;
r100.tw_sm_c_100.twoWS_rw = op;
r100.tw_sm_c_100.twoWS_port_reg = i2c->port;
#ifdef DUMP_I2C_MESSAGES
printk(KERN_DEBUG "%d ", i2c->port);
if (op == FC_READ)
printk("rd(");
else
printk("wr(");
printk("%02x): %02x ", chipaddr, addr);
#endif
/* in that case addr is the only value ->
* we write it twice as baseaddr and val0
* BBTI is doing it like that for ISL6421 at least */
if (i2c->no_base_addr && len == 0 && op == FC_WRITE) {
buf = &addr;
len = 1;
}
while (len != 0) {
bytes_to_transfer = len > 4 ? 4 : len;
r100.tw_sm_c_100.total_bytes = bytes_to_transfer - 1;
r100.tw_sm_c_100.baseaddr = addr;
if (op == FC_READ)
ret = flexcop_i2c_read4(i2c, r100, buf);
else
ret = flexcop_i2c_write4(i2c->fc, r100, buf);
#ifdef DUMP_I2C_MESSAGES
for (i = 0; i < bytes_to_transfer; i++)
printk("%02x ", buf[i]);
#endif
if (ret < 0)
return ret;
buf += bytes_to_transfer;
addr += bytes_to_transfer;
len -= bytes_to_transfer;
}
#ifdef DUMP_I2C_MESSAGES
printk("\n");
#endif
return 0;
}
/* exported for PCI i2c */
EXPORT_SYMBOL(flexcop_i2c_request);
/* master xfer callback for demodulator */
static int flexcop_master_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msgs[], int num)
{
struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
int i, ret = 0;
/* Some drivers use 1 byte or 0 byte reads as probes, which this
* driver doesn't support. These probes will always fail, so this
* hack makes them always succeed. If one knew how, it would of
* course be better to actually do the read. */
if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1)
return 1;
if (mutex_lock_interruptible(&i2c->fc->i2c_mutex))
return -ERESTARTSYS;
for (i = 0; i < num; i++) {
/* reading */
if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) {
ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr,
msgs[i].buf[0], msgs[i+1].buf,
msgs[i+1].len);
i++; /* skip the following message */
} else /* writing */
ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr,
msgs[i].buf[0], &msgs[i].buf[1],
msgs[i].len - 1);
if (ret < 0) {
deb_i2c("i2c master_xfer failed");
break;
}
}
mutex_unlock(&i2c->fc->i2c_mutex);
if (ret == 0)
ret = num;
return ret;
}
static u32 flexcop_i2c_func(struct i2c_adapter *adapter)
{
return I2C_FUNC_I2C;
}
static struct i2c_algorithm flexcop_algo = {
.master_xfer = flexcop_master_xfer,
.functionality = flexcop_i2c_func,
};
int flexcop_i2c_init(struct flexcop_device *fc)
{
int ret;
mutex_init(&fc->i2c_mutex);
fc->fc_i2c_adap[0].fc = fc;
fc->fc_i2c_adap[1].fc = fc;
fc->fc_i2c_adap[2].fc = fc;
fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD;
fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
strlcpy(fc->fc_i2c_adap[0].i2c_adap.name, "B2C2 FlexCop I2C to demod",
sizeof(fc->fc_i2c_adap[0].i2c_adap.name));
strlcpy(fc->fc_i2c_adap[1].i2c_adap.name, "B2C2 FlexCop I2C to eeprom",
sizeof(fc->fc_i2c_adap[1].i2c_adap.name));
strlcpy(fc->fc_i2c_adap[2].i2c_adap.name, "B2C2 FlexCop I2C to tuner",
sizeof(fc->fc_i2c_adap[2].i2c_adap.name));
i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
fc->fc_i2c_adap[0].i2c_adap.algo =
fc->fc_i2c_adap[1].i2c_adap.algo =
fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;
fc->fc_i2c_adap[0].i2c_adap.algo_data =
fc->fc_i2c_adap[1].i2c_adap.algo_data =
fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL;
fc->fc_i2c_adap[0].i2c_adap.dev.parent =
fc->fc_i2c_adap[1].i2c_adap.dev.parent =
fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev;
ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap);
if (ret < 0)
return ret;
ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap);
if (ret < 0)
goto adap_1_failed;
ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap);
if (ret < 0)
goto adap_2_failed;
fc->init_state |= FC_STATE_I2C_INIT;
return 0;
adap_2_failed:
i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
adap_1_failed:
i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
return ret;
}
void flexcop_i2c_exit(struct flexcop_device *fc)
{
if (fc->init_state & FC_STATE_I2C_INIT) {
i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap);
i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
}
fc->init_state &= ~FC_STATE_I2C_INIT;
}

View file

@ -0,0 +1,86 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop-misc.c - miscellaneous functions
* see flexcop.c for copyright information
*/
#include "flexcop.h"
void flexcop_determine_revision(struct flexcop_device *fc)
{
flexcop_ibi_value v = fc->read_ibi_reg(fc,misc_204);
switch (v.misc_204.Rev_N_sig_revision_hi) {
case 0x2:
deb_info("found a FlexCopII.\n");
fc->rev = FLEXCOP_II;
break;
case 0x3:
deb_info("found a FlexCopIIb.\n");
fc->rev = FLEXCOP_IIB;
break;
case 0x0:
deb_info("found a FlexCopIII.\n");
fc->rev = FLEXCOP_III;
break;
default:
err("unknown FlexCop Revision: %x. Please report this to "
"linux-dvb@linuxtv.org.",
v.misc_204.Rev_N_sig_revision_hi);
break;
}
if ((fc->has_32_hw_pid_filter = v.misc_204.Rev_N_sig_caps))
deb_info("this FlexCop has "
"the additional 32 hardware pid filter.\n");
else
deb_info("this FlexCop has "
"the 6 basic main hardware pid filter.\n");
/* bus parts have to decide if hw pid filtering is used or not. */
}
static const char *flexcop_revision_names[] = {
"Unknown chip",
"FlexCopII",
"FlexCopIIb",
"FlexCopIII",
};
static const char *flexcop_device_names[] = {
[FC_UNK] = "Unknown device",
[FC_CABLE] = "Cable2PC/CableStar 2 DVB-C",
[FC_AIR_DVBT] = "Air2PC/AirStar 2 DVB-T",
[FC_AIR_ATSC1] = "Air2PC/AirStar 2 ATSC 1st generation",
[FC_AIR_ATSC2] = "Air2PC/AirStar 2 ATSC 2nd generation",
[FC_AIR_ATSC3] = "Air2PC/AirStar 2 ATSC 3rd generation (HD5000)",
[FC_SKY_REV23] = "Sky2PC/SkyStar 2 DVB-S rev 2.3 (old version)",
[FC_SKY_REV26] = "Sky2PC/SkyStar 2 DVB-S rev 2.6",
[FC_SKY_REV27] = "Sky2PC/SkyStar 2 DVB-S rev 2.7a/u",
[FC_SKY_REV28] = "Sky2PC/SkyStar 2 DVB-S rev 2.8",
};
static const char *flexcop_bus_names[] = {
"USB",
"PCI",
};
void flexcop_device_name(struct flexcop_device *fc,
const char *prefix, const char *suffix)
{
info("%s '%s' at the '%s' bus controlled by a '%s' %s",
prefix, flexcop_device_names[fc->dev_type],
flexcop_bus_names[fc->bus_type],
flexcop_revision_names[fc->rev], suffix);
}
void flexcop_dump_reg(struct flexcop_device *fc,
flexcop_ibi_register reg, int num)
{
flexcop_ibi_value v;
int i;
for (i = 0; i < num; i++) {
v = fc->read_ibi_reg(fc, reg+4*i);
deb_rdump("0x%03x: %08x, ", reg+4*i, v.raw);
}
deb_rdump("\n");
}
EXPORT_SYMBOL(flexcop_dump_reg);

View file

@ -0,0 +1,166 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop-reg.h - register abstraction for FlexCopII, FlexCopIIb and FlexCopIII
* see flexcop.c for copyright information
*/
#ifndef __FLEXCOP_REG_H__
#define __FLEXCOP_REG_H__
typedef enum {
FLEXCOP_UNK = 0,
FLEXCOP_II,
FLEXCOP_IIB,
FLEXCOP_III,
} flexcop_revision_t;
typedef enum {
FC_UNK = 0,
FC_CABLE,
FC_AIR_DVBT,
FC_AIR_ATSC1,
FC_AIR_ATSC2,
FC_AIR_ATSC3,
FC_SKY_REV23,
FC_SKY_REV26,
FC_SKY_REV27,
FC_SKY_REV28,
} flexcop_device_type_t;
typedef enum {
FC_USB = 0,
FC_PCI,
} flexcop_bus_t;
/* FlexCop IBI Registers */
#if defined(__LITTLE_ENDIAN)
#include "flexcop_ibi_value_le.h"
#else
#if defined(__BIG_ENDIAN)
#include "flexcop_ibi_value_be.h"
#else
#error no endian defined
#endif
#endif
#define fc_data_Tag_ID_DVB 0x3e
#define fc_data_Tag_ID_ATSC 0x3f
#define fc_data_Tag_ID_IDSB 0x8b
#define fc_key_code_default 0x1
#define fc_key_code_even 0x2
#define fc_key_code_odd 0x3
extern flexcop_ibi_value ibi_zero;
typedef enum {
FC_I2C_PORT_DEMOD = 1,
FC_I2C_PORT_EEPROM = 2,
FC_I2C_PORT_TUNER = 3,
} flexcop_i2c_port_t;
typedef enum {
FC_WRITE = 0,
FC_READ = 1,
} flexcop_access_op_t;
typedef enum {
FC_SRAM_DEST_NET = 1,
FC_SRAM_DEST_CAI = 2,
FC_SRAM_DEST_CAO = 4,
FC_SRAM_DEST_MEDIA = 8
} flexcop_sram_dest_t;
typedef enum {
FC_SRAM_DEST_TARGET_WAN_USB = 0,
FC_SRAM_DEST_TARGET_DMA1 = 1,
FC_SRAM_DEST_TARGET_DMA2 = 2,
FC_SRAM_DEST_TARGET_FC3_CA = 3
} flexcop_sram_dest_target_t;
typedef enum {
FC_SRAM_2_32KB = 0, /* 64KB */
FC_SRAM_1_32KB = 1, /* 32KB - default fow FCII */
FC_SRAM_1_128KB = 2, /* 128KB */
FC_SRAM_1_48KB = 3, /* 48KB - default for FCIII */
} flexcop_sram_type_t;
typedef enum {
FC_WAN_SPEED_4MBITS = 0,
FC_WAN_SPEED_8MBITS = 1,
FC_WAN_SPEED_12MBITS = 2,
FC_WAN_SPEED_16MBITS = 3,
} flexcop_wan_speed_t;
typedef enum {
FC_DMA_1 = 1,
FC_DMA_2 = 2,
} flexcop_dma_index_t;
typedef enum {
FC_DMA_SUBADDR_0 = 1,
FC_DMA_SUBADDR_1 = 2,
} flexcop_dma_addr_index_t;
/* names of the particular registers */
typedef enum {
dma1_000 = 0x000,
dma1_004 = 0x004,
dma1_008 = 0x008,
dma1_00c = 0x00c,
dma2_010 = 0x010,
dma2_014 = 0x014,
dma2_018 = 0x018,
dma2_01c = 0x01c,
tw_sm_c_100 = 0x100,
tw_sm_c_104 = 0x104,
tw_sm_c_108 = 0x108,
tw_sm_c_10c = 0x10c,
tw_sm_c_110 = 0x110,
lnb_switch_freq_200 = 0x200,
misc_204 = 0x204,
ctrl_208 = 0x208,
irq_20c = 0x20c,
sw_reset_210 = 0x210,
misc_214 = 0x214,
mbox_v8_to_host_218 = 0x218,
mbox_host_to_v8_21c = 0x21c,
pid_filter_300 = 0x300,
pid_filter_304 = 0x304,
pid_filter_308 = 0x308,
pid_filter_30c = 0x30c,
index_reg_310 = 0x310,
pid_n_reg_314 = 0x314,
mac_low_reg_318 = 0x318,
mac_high_reg_31c = 0x31c,
data_tag_400 = 0x400,
card_id_408 = 0x408,
card_id_40c = 0x40c,
mac_address_418 = 0x418,
mac_address_41c = 0x41c,
ci_600 = 0x600,
pi_604 = 0x604,
pi_608 = 0x608,
dvb_reg_60c = 0x60c,
sram_ctrl_reg_700 = 0x700,
net_buf_reg_704 = 0x704,
cai_buf_reg_708 = 0x708,
cao_buf_reg_70c = 0x70c,
media_buf_reg_710 = 0x710,
sram_dest_reg_714 = 0x714,
net_buf_reg_718 = 0x718,
wan_ctrl_reg_71c = 0x71c,
} flexcop_ibi_register;
#define flexcop_set_ibi_value(reg,attr,val) { \
flexcop_ibi_value v = fc->read_ibi_reg(fc,reg); \
v.reg.attr = val; \
fc->write_ibi_reg(fc,reg,v); \
}
#endif

View file

@ -0,0 +1,363 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop-sram.c - functions for controlling the SRAM
* see flexcop.c for copyright information
*/
#include "flexcop.h"
static void flexcop_sram_set_chip(struct flexcop_device *fc,
flexcop_sram_type_t type)
{
flexcop_set_ibi_value(wan_ctrl_reg_71c, sram_chip, type);
}
int flexcop_sram_init(struct flexcop_device *fc)
{
switch (fc->rev) {
case FLEXCOP_II:
case FLEXCOP_IIB:
flexcop_sram_set_chip(fc, FC_SRAM_1_32KB);
break;
case FLEXCOP_III:
flexcop_sram_set_chip(fc, FC_SRAM_1_48KB);
break;
default:
return -EINVAL;
}
return 0;
}
int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest,
flexcop_sram_dest_target_t target)
{
flexcop_ibi_value v;
v = fc->read_ibi_reg(fc, sram_dest_reg_714);
if (fc->rev != FLEXCOP_III && target == FC_SRAM_DEST_TARGET_FC3_CA) {
err("SRAM destination target to available on FlexCopII(b)\n");
return -EINVAL;
}
deb_sram("sram dest: %x target: %x\n", dest, target);
if (dest & FC_SRAM_DEST_NET)
v.sram_dest_reg_714.NET_Dest = target;
if (dest & FC_SRAM_DEST_CAI)
v.sram_dest_reg_714.CAI_Dest = target;
if (dest & FC_SRAM_DEST_CAO)
v.sram_dest_reg_714.CAO_Dest = target;
if (dest & FC_SRAM_DEST_MEDIA)
v.sram_dest_reg_714.MEDIA_Dest = target;
fc->write_ibi_reg(fc,sram_dest_reg_714,v);
udelay(1000); /* TODO delay really necessary */
return 0;
}
EXPORT_SYMBOL(flexcop_sram_set_dest);
void flexcop_wan_set_speed(struct flexcop_device *fc, flexcop_wan_speed_t s)
{
flexcop_set_ibi_value(wan_ctrl_reg_71c,wan_speed_sig,s);
}
EXPORT_SYMBOL(flexcop_wan_set_speed);
void flexcop_sram_ctrl(struct flexcop_device *fc, int usb_wan, int sramdma, int maximumfill)
{
flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
v.sram_dest_reg_714.ctrl_usb_wan = usb_wan;
v.sram_dest_reg_714.ctrl_sramdma = sramdma;
v.sram_dest_reg_714.ctrl_maximumfill = maximumfill;
fc->write_ibi_reg(fc,sram_dest_reg_714,v);
}
EXPORT_SYMBOL(flexcop_sram_ctrl);
#if 0
static void flexcop_sram_write(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
{
int i, retries;
u32 command;
for (i = 0; i < len; i++) {
command = bank | addr | 0x04000000 | (*buf << 0x10);
retries = 2;
while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
mdelay(1);
retries--;
};
if (retries == 0)
printk("%s: SRAM timeout\n", __func__);
write_reg_dw(adapter, 0x700, command);
buf++;
addr++;
}
}
static void flex_sram_read(struct adapter *adapter, u32 bank, u32 addr, u8 *buf, u32 len)
{
int i, retries;
u32 command, value;
for (i = 0; i < len; i++) {
command = bank | addr | 0x04008000;
retries = 10000;
while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
mdelay(1);
retries--;
};
if (retries == 0)
printk("%s: SRAM timeout\n", __func__);
write_reg_dw(adapter, 0x700, command);
retries = 10000;
while (((read_reg_dw(adapter, 0x700) & 0x80000000) != 0) && (retries > 0)) {
mdelay(1);
retries--;
};
if (retries == 0)
printk("%s: SRAM timeout\n", __func__);
value = read_reg_dw(adapter, 0x700) >> 0x10;
*buf = (value & 0xff);
addr++;
buf++;
}
}
static void sram_write_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
{
u32 bank;
bank = 0;
if (adapter->dw_sram_type == 0x20000) {
bank = (addr & 0x18000) << 0x0d;
}
if (adapter->dw_sram_type == 0x00000) {
if ((addr >> 0x0f) == 0)
bank = 0x20000000;
else
bank = 0x10000000;
}
flex_sram_write(adapter, bank, addr & 0x7fff, buf, len);
}
static void sram_read_chunk(struct adapter *adapter, u32 addr, u8 *buf, u16 len)
{
u32 bank;
bank = 0;
if (adapter->dw_sram_type == 0x20000) {
bank = (addr & 0x18000) << 0x0d;
}
if (adapter->dw_sram_type == 0x00000) {
if ((addr >> 0x0f) == 0)
bank = 0x20000000;
else
bank = 0x10000000;
}
flex_sram_read(adapter, bank, addr & 0x7fff, buf, len);
}
static void sram_read(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
{
u32 length;
while (len != 0) {
length = len;
/* check if the address range belongs to the same
* 32K memory chip. If not, the data is read
* from one chip at a time */
if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
}
sram_read_chunk(adapter, addr, buf, length);
addr = addr + length;
buf = buf + length;
len = len - length;
}
}
static void sram_write(struct adapter *adapter, u32 addr, u8 *buf, u32 len)
{
u32 length;
while (len != 0) {
length = len;
/* check if the address range belongs to the same
* 32K memory chip. If not, the data is
* written to one chip at a time */
if ((addr >> 0x0f) != ((addr + len - 1) >> 0x0f)) {
length = (((addr >> 0x0f) + 1) << 0x0f) - addr;
}
sram_write_chunk(adapter, addr, buf, length);
addr = addr + length;
buf = buf + length;
len = len - length;
}
}
static void sram_set_size(struct adapter *adapter, u32 mask)
{
write_reg_dw(adapter, 0x71c,
(mask | (~0x30000 & read_reg_dw(adapter, 0x71c))));
}
static void sram_init(struct adapter *adapter)
{
u32 tmp;
tmp = read_reg_dw(adapter, 0x71c);
write_reg_dw(adapter, 0x71c, 1);
if (read_reg_dw(adapter, 0x71c) != 0) {
write_reg_dw(adapter, 0x71c, tmp);
adapter->dw_sram_type = tmp & 0x30000;
ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
} else {
adapter->dw_sram_type = 0x10000;
ddprintk("%s: dw_sram_type = %x\n", __func__, adapter->dw_sram_type);
}
}
static int sram_test_location(struct adapter *adapter, u32 mask, u32 addr)
{
u8 tmp1, tmp2;
dprintk("%s: mask = %x, addr = %x\n", __func__, mask, addr);
sram_set_size(adapter, mask);
sram_init(adapter);
tmp2 = 0xa5;
tmp1 = 0x4f;
sram_write(adapter, addr, &tmp2, 1);
sram_write(adapter, addr + 4, &tmp1, 1);
tmp2 = 0;
mdelay(20);
sram_read(adapter, addr, &tmp2, 1);
sram_read(adapter, addr, &tmp2, 1);
dprintk("%s: wrote 0xa5, read 0x%2x\n", __func__, tmp2);
if (tmp2 != 0xa5)
return 0;
tmp2 = 0x5a;
tmp1 = 0xf4;
sram_write(adapter, addr, &tmp2, 1);
sram_write(adapter, addr + 4, &tmp1, 1);
tmp2 = 0;
mdelay(20);
sram_read(adapter, addr, &tmp2, 1);
sram_read(adapter, addr, &tmp2, 1);
dprintk("%s: wrote 0x5a, read 0x%2x\n", __func__, tmp2);
if (tmp2 != 0x5a)
return 0;
return 1;
}
static u32 sram_length(struct adapter *adapter)
{
if (adapter->dw_sram_type == 0x10000)
return 32768; /* 32K */
if (adapter->dw_sram_type == 0x00000)
return 65536; /* 64K */
if (adapter->dw_sram_type == 0x20000)
return 131072; /* 128K */
return 32768; /* 32K */
}
/* FlexcopII can work with 32K, 64K or 128K of external SRAM memory.
- for 128K there are 4x32K chips at bank 0,1,2,3.
- for 64K there are 2x32K chips at bank 1,2.
- for 32K there is one 32K chip at bank 0.
FlexCop works only with one bank at a time. The bank is selected
by bits 28-29 of the 0x700 register.
bank 0 covers addresses 0x00000-0x07fff
bank 1 covers addresses 0x08000-0x0ffff
bank 2 covers addresses 0x10000-0x17fff
bank 3 covers addresses 0x18000-0x1ffff */
static int flexcop_sram_detect(struct flexcop_device *fc)
{
flexcop_ibi_value r208, r71c_0, vr71c_1;
r208 = fc->read_ibi_reg(fc, ctrl_208);
fc->write_ibi_reg(fc, ctrl_208, ibi_zero);
r71c_0 = fc->read_ibi_reg(fc, wan_ctrl_reg_71c);
write_reg_dw(adapter, 0x71c, 1);
tmp3 = read_reg_dw(adapter, 0x71c);
dprintk("%s: tmp3 = %x\n", __func__, tmp3);
write_reg_dw(adapter, 0x71c, tmp2);
// check for internal SRAM ???
tmp3--;
if (tmp3 != 0) {
sram_set_size(adapter, 0x10000);
sram_init(adapter);
write_reg_dw(adapter, 0x208, tmp);
dprintk("%s: sram size = 32K\n", __func__);
return 32;
}
if (sram_test_location(adapter, 0x20000, 0x18000) != 0) {
sram_set_size(adapter, 0x20000);
sram_init(adapter);
write_reg_dw(adapter, 0x208, tmp);
dprintk("%s: sram size = 128K\n", __func__);
return 128;
}
if (sram_test_location(adapter, 0x00000, 0x10000) != 0) {
sram_set_size(adapter, 0x00000);
sram_init(adapter);
write_reg_dw(adapter, 0x208, tmp);
dprintk("%s: sram size = 64K\n", __func__);
return 64;
}
if (sram_test_location(adapter, 0x10000, 0x00000) != 0) {
sram_set_size(adapter, 0x10000);
sram_init(adapter);
write_reg_dw(adapter, 0x208, tmp);
dprintk("%s: sram size = 32K\n", __func__);
return 32;
}
sram_set_size(adapter, 0x10000);
sram_init(adapter);
write_reg_dw(adapter, 0x208, tmp);
dprintk("%s: SRAM detection failed. Set to 32K \n", __func__);
return 0;
}
static void sll_detect_sram_size(struct adapter *adapter)
{
sram_detect_for_flex2(adapter);
}
#endif

View file

@ -0,0 +1,325 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop.c - main module part
* Copyright (C) 2004-9 Patrick Boettcher <patrick.boettcher@desy.de>
* based on skystar2-driver Copyright (C) 2003 Vadim Catana, skystar@moldova.cc
*
* Acknowledgements:
* John Jurrius from BBTI, Inc. for extensive support
* with code examples and data books
* Bjarne Steinsbo, bjarne at steinsbo.com (some ideas for rewriting)
*
* Contributions to the skystar2-driver have been done by
* Vincenzo Di Massa, hawk.it at tiscalinet.it (several DiSEqC fixes)
* Roberto Ragusa, r.ragusa at libero.it (polishing, restyling the code)
* Uwe Bugla, uwe.bugla at gmx.de (doing tests, restyling code, writing docu)
* Niklas Peinecke, peinecke at gdv.uni-hannover.de (hardware pid/mac
* filtering)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "flexcop.h"
#define DRIVER_NAME "B2C2 FlexcopII/II(b)/III digital TV receiver chip"
#define DRIVER_AUTHOR "Patrick Boettcher <patrick.boettcher@desy.de"
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
#define DEBSTATUS ""
#else
#define DEBSTATUS " (debugging is not enabled)"
#endif
int b2c2_flexcop_debug;
EXPORT_SYMBOL_GPL(b2c2_flexcop_debug);
module_param_named(debug, b2c2_flexcop_debug, int, 0644);
MODULE_PARM_DESC(debug,
"set debug level (1=info,2=tuner,4=i2c,8=ts,"
"16=sram,32=reg (|-able))."
DEBSTATUS);
#undef DEBSTATUS
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* global zero for ibi values */
flexcop_ibi_value ibi_zero;
static int flexcop_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct flexcop_device *fc = dvbdmxfeed->demux->priv;
return flexcop_pid_feed_control(fc, dvbdmxfeed, 1);
}
static int flexcop_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct flexcop_device *fc = dvbdmxfeed->demux->priv;
return flexcop_pid_feed_control(fc, dvbdmxfeed, 0);
}
static int flexcop_dvb_init(struct flexcop_device *fc)
{
int ret = dvb_register_adapter(&fc->dvb_adapter,
"FlexCop Digital TV device", fc->owner,
fc->dev, adapter_nr);
if (ret < 0) {
err("error registering DVB adapter");
return ret;
}
fc->dvb_adapter.priv = fc;
fc->demux.dmx.capabilities = (DMX_TS_FILTERING | DMX_SECTION_FILTERING
| DMX_MEMORY_BASED_FILTERING);
fc->demux.priv = fc;
fc->demux.filternum = fc->demux.feednum = FC_MAX_FEED;
fc->demux.start_feed = flexcop_dvb_start_feed;
fc->demux.stop_feed = flexcop_dvb_stop_feed;
fc->demux.write_to_decoder = NULL;
ret = dvb_dmx_init(&fc->demux);
if (ret < 0) {
err("dvb_dmx failed: error %d", ret);
goto err_dmx;
}
fc->hw_frontend.source = DMX_FRONTEND_0;
fc->dmxdev.filternum = fc->demux.feednum;
fc->dmxdev.demux = &fc->demux.dmx;
fc->dmxdev.capabilities = 0;
ret = dvb_dmxdev_init(&fc->dmxdev, &fc->dvb_adapter);
if (ret < 0) {
err("dvb_dmxdev_init failed: error %d", ret);
goto err_dmx_dev;
}
ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->hw_frontend);
if (ret < 0) {
err("adding hw_frontend to dmx failed: error %d", ret);
goto err_dmx_add_hw_frontend;
}
fc->mem_frontend.source = DMX_MEMORY_FE;
ret = fc->demux.dmx.add_frontend(&fc->demux.dmx, &fc->mem_frontend);
if (ret < 0) {
err("adding mem_frontend to dmx failed: error %d", ret);
goto err_dmx_add_mem_frontend;
}
ret = fc->demux.dmx.connect_frontend(&fc->demux.dmx, &fc->hw_frontend);
if (ret < 0) {
err("connect frontend failed: error %d", ret);
goto err_connect_frontend;
}
ret = dvb_net_init(&fc->dvb_adapter, &fc->dvbnet, &fc->demux.dmx);
if (ret < 0) {
err("dvb_net_init failed: error %d", ret);
goto err_net;
}
fc->init_state |= FC_STATE_DVB_INIT;
return 0;
err_net:
fc->demux.dmx.disconnect_frontend(&fc->demux.dmx);
err_connect_frontend:
fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->mem_frontend);
err_dmx_add_mem_frontend:
fc->demux.dmx.remove_frontend(&fc->demux.dmx, &fc->hw_frontend);
err_dmx_add_hw_frontend:
dvb_dmxdev_release(&fc->dmxdev);
err_dmx_dev:
dvb_dmx_release(&fc->demux);
err_dmx:
dvb_unregister_adapter(&fc->dvb_adapter);
return ret;
}
static void flexcop_dvb_exit(struct flexcop_device *fc)
{
if (fc->init_state & FC_STATE_DVB_INIT) {
dvb_net_release(&fc->dvbnet);
fc->demux.dmx.close(&fc->demux.dmx);
fc->demux.dmx.remove_frontend(&fc->demux.dmx,
&fc->mem_frontend);
fc->demux.dmx.remove_frontend(&fc->demux.dmx,
&fc->hw_frontend);
dvb_dmxdev_release(&fc->dmxdev);
dvb_dmx_release(&fc->demux);
dvb_unregister_adapter(&fc->dvb_adapter);
deb_info("deinitialized dvb stuff\n");
}
fc->init_state &= ~FC_STATE_DVB_INIT;
}
/* these methods are necessary to achieve the long-term-goal of hiding the
* struct flexcop_device from the bus-parts */
void flexcop_pass_dmx_data(struct flexcop_device *fc, u8 *buf, u32 len)
{
dvb_dmx_swfilter(&fc->demux, buf, len);
}
EXPORT_SYMBOL(flexcop_pass_dmx_data);
void flexcop_pass_dmx_packets(struct flexcop_device *fc, u8 *buf, u32 no)
{
dvb_dmx_swfilter_packets(&fc->demux, buf, no);
}
EXPORT_SYMBOL(flexcop_pass_dmx_packets);
static void flexcop_reset(struct flexcop_device *fc)
{
flexcop_ibi_value v210, v204;
/* reset the flexcop itself */
fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
v210.raw = 0;
v210.sw_reset_210.reset_block_000 = 1;
v210.sw_reset_210.reset_block_100 = 1;
v210.sw_reset_210.reset_block_200 = 1;
v210.sw_reset_210.reset_block_300 = 1;
v210.sw_reset_210.reset_block_400 = 1;
v210.sw_reset_210.reset_block_500 = 1;
v210.sw_reset_210.reset_block_600 = 1;
v210.sw_reset_210.reset_block_700 = 1;
v210.sw_reset_210.Block_reset_enable = 0xb2;
v210.sw_reset_210.Special_controls = 0xc259;
fc->write_ibi_reg(fc,sw_reset_210,v210);
msleep(1);
/* reset the periphical devices */
v204 = fc->read_ibi_reg(fc,misc_204);
v204.misc_204.Per_reset_sig = 0;
fc->write_ibi_reg(fc,misc_204,v204);
msleep(1);
v204.misc_204.Per_reset_sig = 1;
fc->write_ibi_reg(fc,misc_204,v204);
}
void flexcop_reset_block_300(struct flexcop_device *fc)
{
flexcop_ibi_value v208_save = fc->read_ibi_reg(fc, ctrl_208),
v210 = fc->read_ibi_reg(fc, sw_reset_210);
deb_rdump("208: %08x, 210: %08x\n", v208_save.raw, v210.raw);
fc->write_ibi_reg(fc,ctrl_208,ibi_zero);
v210.sw_reset_210.reset_block_300 = 1;
v210.sw_reset_210.Block_reset_enable = 0xb2;
fc->write_ibi_reg(fc,sw_reset_210,v210);
fc->write_ibi_reg(fc,ctrl_208,v208_save);
}
struct flexcop_device *flexcop_device_kmalloc(size_t bus_specific_len)
{
void *bus;
struct flexcop_device *fc = kzalloc(sizeof(struct flexcop_device),
GFP_KERNEL);
if (!fc) {
err("no memory");
return NULL;
}
bus = kzalloc(bus_specific_len, GFP_KERNEL);
if (!bus) {
err("no memory");
kfree(fc);
return NULL;
}
fc->bus_specific = bus;
return fc;
}
EXPORT_SYMBOL(flexcop_device_kmalloc);
void flexcop_device_kfree(struct flexcop_device *fc)
{
kfree(fc->bus_specific);
kfree(fc);
}
EXPORT_SYMBOL(flexcop_device_kfree);
int flexcop_device_initialize(struct flexcop_device *fc)
{
int ret;
ibi_zero.raw = 0;
flexcop_reset(fc);
flexcop_determine_revision(fc);
flexcop_sram_init(fc);
flexcop_hw_filter_init(fc);
flexcop_smc_ctrl(fc, 0);
ret = flexcop_dvb_init(fc);
if (ret)
goto error;
/* i2c has to be done before doing EEProm stuff -
* because the EEProm is accessed via i2c */
ret = flexcop_i2c_init(fc);
if (ret)
goto error;
/* do the MAC address reading after initializing the dvb_adapter */
if (fc->get_mac_addr(fc, 0) == 0) {
u8 *b = fc->dvb_adapter.proposed_mac;
info("MAC address = %pM", b);
flexcop_set_mac_filter(fc,b);
flexcop_mac_filter_ctrl(fc,1);
} else
warn("reading of MAC address failed.\n");
ret = flexcop_frontend_init(fc);
if (ret)
goto error;
flexcop_device_name(fc,"initialization of","complete");
return 0;
error:
flexcop_device_exit(fc);
return ret;
}
EXPORT_SYMBOL(flexcop_device_initialize);
void flexcop_device_exit(struct flexcop_device *fc)
{
flexcop_frontend_exit(fc);
flexcop_i2c_exit(fc);
flexcop_dvb_exit(fc);
}
EXPORT_SYMBOL(flexcop_device_exit);
static int flexcop_module_init(void)
{
info(DRIVER_NAME " loaded successfully");
return 0;
}
static void flexcop_module_cleanup(void)
{
info(DRIVER_NAME " unloaded successfully");
}
module_init(flexcop_module_init);
module_exit(flexcop_module_cleanup);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_NAME);
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,29 @@
/*
* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* flexcop.h - private header file for all flexcop-chip-source files
* see flexcop.c for copyright information
*/
#ifndef __FLEXCOP_H__
#define __FLEXCOP_H___
#define FC_LOG_PREFIX "b2c2-flexcop"
#include "flexcop-common.h"
extern int b2c2_flexcop_debug;
/* debug */
#ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
#define dprintk(level,args...) \
do { if ((b2c2_flexcop_debug & level)) printk(args); } while (0)
#else
#define dprintk(level,args...)
#endif
#define deb_info(args...) dprintk(0x01, args)
#define deb_tuner(args...) dprintk(0x02, args)
#define deb_i2c(args...) dprintk(0x04, args)
#define deb_ts(args...) dprintk(0x08, args)
#define deb_sram(args...) dprintk(0x10, args)
#define deb_rdump(args...) dprintk(0x20, args)
#endif

View file

@ -0,0 +1,455 @@
/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* register descriptions
* see flexcop.c for copyright information
*/
/* This file is automatically generated, do not edit things here. */
#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
#define __FLEXCOP_IBI_VALUE_INCLUDED__
typedef union {
u32 raw;
struct {
u32 dma_address0 :30;
u32 dma_0No_update : 1;
u32 dma_0start : 1;
} dma_0x0;
struct {
u32 dma_addr_size :24;
u32 DMA_maxpackets : 8;
} dma_0x4_remap;
struct {
u32 dma_addr_size :24;
u32 unused : 1;
u32 dma1timer : 7;
} dma_0x4_read;
struct {
u32 dma_addr_size :24;
u32 dmatimer : 7;
u32 unused : 1;
} dma_0x4_write;
struct {
u32 dma_cur_addr :30;
u32 unused : 2;
} dma_0x8;
struct {
u32 dma_address1 :30;
u32 remap_enable : 1;
u32 dma_1start : 1;
} dma_0xc;
struct {
u32 st_done : 1;
u32 no_base_addr_ack_error : 1;
u32 twoWS_port_reg : 2;
u32 total_bytes : 2;
u32 twoWS_rw : 1;
u32 working_start : 1;
u32 data1_reg : 8;
u32 baseaddr : 8;
u32 reserved1 : 1;
u32 chipaddr : 7;
} tw_sm_c_100;
struct {
u32 unused : 6;
u32 force_stop : 1;
u32 exlicit_stops : 1;
u32 data4_reg : 8;
u32 data3_reg : 8;
u32 data2_reg : 8;
} tw_sm_c_104;
struct {
u32 reserved2 :19;
u32 tlo1 : 5;
u32 reserved1 : 2;
u32 thi1 : 6;
} tw_sm_c_108;
struct {
u32 reserved2 :19;
u32 tlo1 : 5;
u32 reserved1 : 2;
u32 thi1 : 6;
} tw_sm_c_10c;
struct {
u32 reserved2 :19;
u32 tlo1 : 5;
u32 reserved1 : 2;
u32 thi1 : 6;
} tw_sm_c_110;
struct {
u32 LNB_CTLPrescaler_sig : 2;
u32 LNB_CTLLowCount_sig :15;
u32 LNB_CTLHighCount_sig :15;
} lnb_switch_freq_200;
struct {
u32 Rev_N_sig_reserved2 : 1;
u32 Rev_N_sig_caps : 1;
u32 Rev_N_sig_reserved1 : 2;
u32 Rev_N_sig_revision_hi : 4;
u32 reserved :20;
u32 Per_reset_sig : 1;
u32 LNB_L_H_sig : 1;
u32 ACPI3_sig : 1;
u32 ACPI1_sig : 1;
} misc_204;
struct {
u32 unused : 9;
u32 Mailbox_from_V8_Enable_sig : 1;
u32 DMA2_Size_IRQ_Enable_sig : 1;
u32 DMA1_Size_IRQ_Enable_sig : 1;
u32 DMA2_Timer_Enable_sig : 1;
u32 DMA2_IRQ_Enable_sig : 1;
u32 DMA1_Timer_Enable_sig : 1;
u32 DMA1_IRQ_Enable_sig : 1;
u32 Rcv_Data_sig : 1;
u32 MAC_filter_Mode_sig : 1;
u32 Multi2_Enable_sig : 1;
u32 Per_CA_Enable_sig : 1;
u32 SMC_Enable_sig : 1;
u32 CA_Enable_sig : 1;
u32 WAN_CA_Enable_sig : 1;
u32 WAN_Enable_sig : 1;
u32 Mask_filter_sig : 1;
u32 Null_filter_sig : 1;
u32 ECM_filter_sig : 1;
u32 EMM_filter_sig : 1;
u32 PMT_filter_sig : 1;
u32 PCR_filter_sig : 1;
u32 Stream2_filter_sig : 1;
u32 Stream1_filter_sig : 1;
} ctrl_208;
struct {
u32 reserved :21;
u32 Transport_Error : 1;
u32 LLC_SNAP_FLAG_set : 1;
u32 Continuity_error_flag : 1;
u32 Data_receiver_error : 1;
u32 Mailbox_from_V8_Status_sig : 1;
u32 DMA2_Size_IRQ_Status : 1;
u32 DMA1_Size_IRQ_Status : 1;
u32 DMA2_Timer_Status : 1;
u32 DMA2_IRQ_Status : 1;
u32 DMA1_Timer_Status : 1;
u32 DMA1_IRQ_Status : 1;
} irq_20c;
struct {
u32 Special_controls :16;
u32 Block_reset_enable : 8;
u32 reset_block_700 : 1;
u32 reset_block_600 : 1;
u32 reset_block_500 : 1;
u32 reset_block_400 : 1;
u32 reset_block_300 : 1;
u32 reset_block_200 : 1;
u32 reset_block_100 : 1;
u32 reset_block_000 : 1;
} sw_reset_210;
struct {
u32 unused2 :20;
u32 polarity_PS_ERR_sig : 1;
u32 polarity_PS_SYNC_sig : 1;
u32 polarity_PS_VALID_sig : 1;
u32 polarity_PS_CLK_sig : 1;
u32 unused1 : 3;
u32 s2p_sel_sig : 1;
u32 section_pkg_enable_sig : 1;
u32 halt_V8_sig : 1;
u32 v2WS_oe_sig : 1;
u32 vuart_oe_sig : 1;
} misc_214;
struct {
u32 Mailbox_from_V8 :32;
} mbox_v8_to_host_218;
struct {
u32 sysramaccess_busmuster : 1;
u32 sysramaccess_write : 1;
u32 unused : 7;
u32 sysramaccess_addr :15;
u32 sysramaccess_data : 8;
} mbox_host_to_v8_21c;
struct {
u32 debug_fifo_problem : 1;
u32 debug_flag_write_status00 : 1;
u32 Stream2_trans : 1;
u32 Stream2_PID :13;
u32 debug_flag_pid_saved : 1;
u32 MAC_Multicast_filter : 1;
u32 Stream1_trans : 1;
u32 Stream1_PID :13;
} pid_filter_300;
struct {
u32 reserved : 2;
u32 PMT_trans : 1;
u32 PMT_PID :13;
u32 debug_overrun2 : 1;
u32 debug_overrun3 : 1;
u32 PCR_trans : 1;
u32 PCR_PID :13;
} pid_filter_304;
struct {
u32 reserved : 2;
u32 ECM_trans : 1;
u32 ECM_PID :13;
u32 EMM_filter_6 : 1;
u32 EMM_filter_4 : 1;
u32 EMM_trans : 1;
u32 EMM_PID :13;
} pid_filter_308;
struct {
u32 unused2 : 3;
u32 Group_mask :13;
u32 unused1 : 2;
u32 Group_trans : 1;
u32 Group_PID :13;
} pid_filter_30c_ext_ind_0_7;
struct {
u32 unused :15;
u32 net_master_read :17;
} pid_filter_30c_ext_ind_1;
struct {
u32 unused :15;
u32 net_master_write :17;
} pid_filter_30c_ext_ind_2;
struct {
u32 unused :15;
u32 next_net_master_write :17;
} pid_filter_30c_ext_ind_3;
struct {
u32 reserved2 : 5;
u32 stack_read :10;
u32 reserved1 : 6;
u32 state_write :10;
u32 unused1 : 1;
} pid_filter_30c_ext_ind_4;
struct {
u32 unused :22;
u32 stack_cnt :10;
} pid_filter_30c_ext_ind_5;
struct {
u32 unused : 4;
u32 data_size_reg :12;
u32 write_status4 : 2;
u32 write_status1 : 2;
u32 pid_fsm_save_reg300 : 2;
u32 pid_fsm_save_reg4 : 2;
u32 pid_fsm_save_reg3 : 2;
u32 pid_fsm_save_reg2 : 2;
u32 pid_fsm_save_reg1 : 2;
u32 pid_fsm_save_reg0 : 2;
} pid_filter_30c_ext_ind_6;
struct {
u32 unused :22;
u32 pass_alltables : 1;
u32 AB_select : 1;
u32 extra_index_reg : 3;
u32 index_reg : 5;
} index_reg_310;
struct {
u32 reserved :17;
u32 PID_enable_bit : 1;
u32 PID_trans : 1;
u32 PID :13;
} pid_n_reg_314;
struct {
u32 reserved : 6;
u32 HighAB_bit : 1;
u32 Enable_bit : 1;
u32 A6_byte : 8;
u32 A5_byte : 8;
u32 A4_byte : 8;
} mac_low_reg_318;
struct {
u32 reserved : 8;
u32 A3_byte : 8;
u32 A2_byte : 8;
u32 A1_byte : 8;
} mac_high_reg_31c;
struct {
u32 data_Tag_ID :16;
u32 reserved :16;
} data_tag_400;
struct {
u32 Card_IDbyte3 : 8;
u32 Card_IDbyte4 : 8;
u32 Card_IDbyte5 : 8;
u32 Card_IDbyte6 : 8;
} card_id_408;
struct {
u32 Card_IDbyte1 : 8;
u32 Card_IDbyte2 : 8;
} card_id_40c;
struct {
u32 MAC6 : 8;
u32 MAC3 : 8;
u32 MAC2 : 8;
u32 MAC1 : 8;
} mac_address_418;
struct {
u32 reserved :16;
u32 MAC8 : 8;
u32 MAC7 : 8;
} mac_address_41c;
struct {
u32 reserved :21;
u32 txbuffempty : 1;
u32 ReceiveByteFrameError : 1;
u32 ReceiveDataReady : 1;
u32 transmitter_data_byte : 8;
} ci_600;
struct {
u32 pi_component_reg : 3;
u32 pi_rw : 1;
u32 pi_ha :20;
u32 pi_d : 8;
} pi_604;
struct {
u32 pi_busy_n : 1;
u32 pi_wait_n : 1;
u32 pi_timeout_status : 1;
u32 pi_CiMax_IRQ_n : 1;
u32 config_cclk : 1;
u32 config_cs_n : 1;
u32 config_wr_n : 1;
u32 config_Prog_n : 1;
u32 config_Init_stat : 1;
u32 config_Done_stat : 1;
u32 pcmcia_b_mod_pwr_n : 1;
u32 pcmcia_a_mod_pwr_n : 1;
u32 reserved : 3;
u32 Timer_addr : 5;
u32 unused : 1;
u32 timer_data : 7;
u32 Timer_Load_req : 1;
u32 Timer_Read_req : 1;
u32 oncecycle_read : 1;
u32 serialReset : 1;
} pi_608;
struct {
u32 reserved : 6;
u32 rw_flag : 1;
u32 dvb_en : 1;
u32 key_array_row : 5;
u32 key_array_col : 3;
u32 key_code : 2;
u32 key_enable : 1;
u32 PID :13;
} dvb_reg_60c;
struct {
u32 start_sram_ibi : 1;
u32 reserved2 : 1;
u32 ce_pin_reg : 1;
u32 oe_pin_reg : 1;
u32 reserved1 : 3;
u32 sc_xfer_bit : 1;
u32 sram_data : 8;
u32 sram_rw : 1;
u32 sram_addr :15;
} sram_ctrl_reg_700;
struct {
u32 net_addr_write :16;
u32 net_addr_read :16;
} net_buf_reg_704;
struct {
u32 cai_cnt : 4;
u32 reserved2 : 6;
u32 cai_write :11;
u32 reserved1 : 5;
u32 cai_read :11;
} cai_buf_reg_708;
struct {
u32 cao_cnt : 4;
u32 reserved2 : 6;
u32 cap_write :11;
u32 reserved1 : 5;
u32 cao_read :11;
} cao_buf_reg_70c;
struct {
u32 media_cnt : 4;
u32 reserved2 : 6;
u32 media_write :11;
u32 reserved1 : 5;
u32 media_read :11;
} media_buf_reg_710;
struct {
u32 reserved :17;
u32 ctrl_maximumfill : 1;
u32 ctrl_sramdma : 1;
u32 ctrl_usb_wan : 1;
u32 cao_ovflow_error : 1;
u32 cai_ovflow_error : 1;
u32 media_ovflow_error : 1;
u32 net_ovflow_error : 1;
u32 MEDIA_Dest : 2;
u32 CAO_Dest : 2;
u32 CAI_Dest : 2;
u32 NET_Dest : 2;
} sram_dest_reg_714;
struct {
u32 reserved3 :11;
u32 net_addr_write : 1;
u32 reserved2 : 3;
u32 net_addr_read : 1;
u32 reserved1 : 4;
u32 net_cnt :12;
} net_buf_reg_718;
struct {
u32 reserved3 : 4;
u32 wan_pkt_frame : 4;
u32 reserved2 : 4;
u32 sram_memmap : 2;
u32 sram_chip : 2;
u32 wan_wait_state : 8;
u32 reserved1 : 6;
u32 wan_speed_sig : 2;
} wan_ctrl_reg_71c;
} flexcop_ibi_value;
#endif

View file

@ -0,0 +1,455 @@
/* Linux driver for digital TV devices equipped with B2C2 FlexcopII(b)/III
* register descriptions
* see flexcop.c for copyright information
*/
/* This file is automatically generated, do not edit things here. */
#ifndef __FLEXCOP_IBI_VALUE_INCLUDED__
#define __FLEXCOP_IBI_VALUE_INCLUDED__
typedef union {
u32 raw;
struct {
u32 dma_0start : 1;
u32 dma_0No_update : 1;
u32 dma_address0 :30;
} dma_0x0;
struct {
u32 DMA_maxpackets : 8;
u32 dma_addr_size :24;
} dma_0x4_remap;
struct {
u32 dma1timer : 7;
u32 unused : 1;
u32 dma_addr_size :24;
} dma_0x4_read;
struct {
u32 unused : 1;
u32 dmatimer : 7;
u32 dma_addr_size :24;
} dma_0x4_write;
struct {
u32 unused : 2;
u32 dma_cur_addr :30;
} dma_0x8;
struct {
u32 dma_1start : 1;
u32 remap_enable : 1;
u32 dma_address1 :30;
} dma_0xc;
struct {
u32 chipaddr : 7;
u32 reserved1 : 1;
u32 baseaddr : 8;
u32 data1_reg : 8;
u32 working_start : 1;
u32 twoWS_rw : 1;
u32 total_bytes : 2;
u32 twoWS_port_reg : 2;
u32 no_base_addr_ack_error : 1;
u32 st_done : 1;
} tw_sm_c_100;
struct {
u32 data2_reg : 8;
u32 data3_reg : 8;
u32 data4_reg : 8;
u32 exlicit_stops : 1;
u32 force_stop : 1;
u32 unused : 6;
} tw_sm_c_104;
struct {
u32 thi1 : 6;
u32 reserved1 : 2;
u32 tlo1 : 5;
u32 reserved2 :19;
} tw_sm_c_108;
struct {
u32 thi1 : 6;
u32 reserved1 : 2;
u32 tlo1 : 5;
u32 reserved2 :19;
} tw_sm_c_10c;
struct {
u32 thi1 : 6;
u32 reserved1 : 2;
u32 tlo1 : 5;
u32 reserved2 :19;
} tw_sm_c_110;
struct {
u32 LNB_CTLHighCount_sig :15;
u32 LNB_CTLLowCount_sig :15;
u32 LNB_CTLPrescaler_sig : 2;
} lnb_switch_freq_200;
struct {
u32 ACPI1_sig : 1;
u32 ACPI3_sig : 1;
u32 LNB_L_H_sig : 1;
u32 Per_reset_sig : 1;
u32 reserved :20;
u32 Rev_N_sig_revision_hi : 4;
u32 Rev_N_sig_reserved1 : 2;
u32 Rev_N_sig_caps : 1;
u32 Rev_N_sig_reserved2 : 1;
} misc_204;
struct {
u32 Stream1_filter_sig : 1;
u32 Stream2_filter_sig : 1;
u32 PCR_filter_sig : 1;
u32 PMT_filter_sig : 1;
u32 EMM_filter_sig : 1;
u32 ECM_filter_sig : 1;
u32 Null_filter_sig : 1;
u32 Mask_filter_sig : 1;
u32 WAN_Enable_sig : 1;
u32 WAN_CA_Enable_sig : 1;
u32 CA_Enable_sig : 1;
u32 SMC_Enable_sig : 1;
u32 Per_CA_Enable_sig : 1;
u32 Multi2_Enable_sig : 1;
u32 MAC_filter_Mode_sig : 1;
u32 Rcv_Data_sig : 1;
u32 DMA1_IRQ_Enable_sig : 1;
u32 DMA1_Timer_Enable_sig : 1;
u32 DMA2_IRQ_Enable_sig : 1;
u32 DMA2_Timer_Enable_sig : 1;
u32 DMA1_Size_IRQ_Enable_sig : 1;
u32 DMA2_Size_IRQ_Enable_sig : 1;
u32 Mailbox_from_V8_Enable_sig : 1;
u32 unused : 9;
} ctrl_208;
struct {
u32 DMA1_IRQ_Status : 1;
u32 DMA1_Timer_Status : 1;
u32 DMA2_IRQ_Status : 1;
u32 DMA2_Timer_Status : 1;
u32 DMA1_Size_IRQ_Status : 1;
u32 DMA2_Size_IRQ_Status : 1;
u32 Mailbox_from_V8_Status_sig : 1;
u32 Data_receiver_error : 1;
u32 Continuity_error_flag : 1;
u32 LLC_SNAP_FLAG_set : 1;
u32 Transport_Error : 1;
u32 reserved :21;
} irq_20c;
struct {
u32 reset_block_000 : 1;
u32 reset_block_100 : 1;
u32 reset_block_200 : 1;
u32 reset_block_300 : 1;
u32 reset_block_400 : 1;
u32 reset_block_500 : 1;
u32 reset_block_600 : 1;
u32 reset_block_700 : 1;
u32 Block_reset_enable : 8;
u32 Special_controls :16;
} sw_reset_210;
struct {
u32 vuart_oe_sig : 1;
u32 v2WS_oe_sig : 1;
u32 halt_V8_sig : 1;
u32 section_pkg_enable_sig : 1;
u32 s2p_sel_sig : 1;
u32 unused1 : 3;
u32 polarity_PS_CLK_sig : 1;
u32 polarity_PS_VALID_sig : 1;
u32 polarity_PS_SYNC_sig : 1;
u32 polarity_PS_ERR_sig : 1;
u32 unused2 :20;
} misc_214;
struct {
u32 Mailbox_from_V8 :32;
} mbox_v8_to_host_218;
struct {
u32 sysramaccess_data : 8;
u32 sysramaccess_addr :15;
u32 unused : 7;
u32 sysramaccess_write : 1;
u32 sysramaccess_busmuster : 1;
} mbox_host_to_v8_21c;
struct {
u32 Stream1_PID :13;
u32 Stream1_trans : 1;
u32 MAC_Multicast_filter : 1;
u32 debug_flag_pid_saved : 1;
u32 Stream2_PID :13;
u32 Stream2_trans : 1;
u32 debug_flag_write_status00 : 1;
u32 debug_fifo_problem : 1;
} pid_filter_300;
struct {
u32 PCR_PID :13;
u32 PCR_trans : 1;
u32 debug_overrun3 : 1;
u32 debug_overrun2 : 1;
u32 PMT_PID :13;
u32 PMT_trans : 1;
u32 reserved : 2;
} pid_filter_304;
struct {
u32 EMM_PID :13;
u32 EMM_trans : 1;
u32 EMM_filter_4 : 1;
u32 EMM_filter_6 : 1;
u32 ECM_PID :13;
u32 ECM_trans : 1;
u32 reserved : 2;
} pid_filter_308;
struct {
u32 Group_PID :13;
u32 Group_trans : 1;
u32 unused1 : 2;
u32 Group_mask :13;
u32 unused2 : 3;
} pid_filter_30c_ext_ind_0_7;
struct {
u32 net_master_read :17;
u32 unused :15;
} pid_filter_30c_ext_ind_1;
struct {
u32 net_master_write :17;
u32 unused :15;
} pid_filter_30c_ext_ind_2;
struct {
u32 next_net_master_write :17;
u32 unused :15;
} pid_filter_30c_ext_ind_3;
struct {
u32 unused1 : 1;
u32 state_write :10;
u32 reserved1 : 6;
u32 stack_read :10;
u32 reserved2 : 5;
} pid_filter_30c_ext_ind_4;
struct {
u32 stack_cnt :10;
u32 unused :22;
} pid_filter_30c_ext_ind_5;
struct {
u32 pid_fsm_save_reg0 : 2;
u32 pid_fsm_save_reg1 : 2;
u32 pid_fsm_save_reg2 : 2;
u32 pid_fsm_save_reg3 : 2;
u32 pid_fsm_save_reg4 : 2;
u32 pid_fsm_save_reg300 : 2;
u32 write_status1 : 2;
u32 write_status4 : 2;
u32 data_size_reg :12;
u32 unused : 4;
} pid_filter_30c_ext_ind_6;
struct {
u32 index_reg : 5;
u32 extra_index_reg : 3;
u32 AB_select : 1;
u32 pass_alltables : 1;
u32 unused :22;
} index_reg_310;
struct {
u32 PID :13;
u32 PID_trans : 1;
u32 PID_enable_bit : 1;
u32 reserved :17;
} pid_n_reg_314;
struct {
u32 A4_byte : 8;
u32 A5_byte : 8;
u32 A6_byte : 8;
u32 Enable_bit : 1;
u32 HighAB_bit : 1;
u32 reserved : 6;
} mac_low_reg_318;
struct {
u32 A1_byte : 8;
u32 A2_byte : 8;
u32 A3_byte : 8;
u32 reserved : 8;
} mac_high_reg_31c;
struct {
u32 reserved :16;
u32 data_Tag_ID :16;
} data_tag_400;
struct {
u32 Card_IDbyte6 : 8;
u32 Card_IDbyte5 : 8;
u32 Card_IDbyte4 : 8;
u32 Card_IDbyte3 : 8;
} card_id_408;
struct {
u32 Card_IDbyte2 : 8;
u32 Card_IDbyte1 : 8;
} card_id_40c;
struct {
u32 MAC1 : 8;
u32 MAC2 : 8;
u32 MAC3 : 8;
u32 MAC6 : 8;
} mac_address_418;
struct {
u32 MAC7 : 8;
u32 MAC8 : 8;
u32 reserved :16;
} mac_address_41c;
struct {
u32 transmitter_data_byte : 8;
u32 ReceiveDataReady : 1;
u32 ReceiveByteFrameError : 1;
u32 txbuffempty : 1;
u32 reserved :21;
} ci_600;
struct {
u32 pi_d : 8;
u32 pi_ha :20;
u32 pi_rw : 1;
u32 pi_component_reg : 3;
} pi_604;
struct {
u32 serialReset : 1;
u32 oncecycle_read : 1;
u32 Timer_Read_req : 1;
u32 Timer_Load_req : 1;
u32 timer_data : 7;
u32 unused : 1;
u32 Timer_addr : 5;
u32 reserved : 3;
u32 pcmcia_a_mod_pwr_n : 1;
u32 pcmcia_b_mod_pwr_n : 1;
u32 config_Done_stat : 1;
u32 config_Init_stat : 1;
u32 config_Prog_n : 1;
u32 config_wr_n : 1;
u32 config_cs_n : 1;
u32 config_cclk : 1;
u32 pi_CiMax_IRQ_n : 1;
u32 pi_timeout_status : 1;
u32 pi_wait_n : 1;
u32 pi_busy_n : 1;
} pi_608;
struct {
u32 PID :13;
u32 key_enable : 1;
u32 key_code : 2;
u32 key_array_col : 3;
u32 key_array_row : 5;
u32 dvb_en : 1;
u32 rw_flag : 1;
u32 reserved : 6;
} dvb_reg_60c;
struct {
u32 sram_addr :15;
u32 sram_rw : 1;
u32 sram_data : 8;
u32 sc_xfer_bit : 1;
u32 reserved1 : 3;
u32 oe_pin_reg : 1;
u32 ce_pin_reg : 1;
u32 reserved2 : 1;
u32 start_sram_ibi : 1;
} sram_ctrl_reg_700;
struct {
u32 net_addr_read :16;
u32 net_addr_write :16;
} net_buf_reg_704;
struct {
u32 cai_read :11;
u32 reserved1 : 5;
u32 cai_write :11;
u32 reserved2 : 6;
u32 cai_cnt : 4;
} cai_buf_reg_708;
struct {
u32 cao_read :11;
u32 reserved1 : 5;
u32 cap_write :11;
u32 reserved2 : 6;
u32 cao_cnt : 4;
} cao_buf_reg_70c;
struct {
u32 media_read :11;
u32 reserved1 : 5;
u32 media_write :11;
u32 reserved2 : 6;
u32 media_cnt : 4;
} media_buf_reg_710;
struct {
u32 NET_Dest : 2;
u32 CAI_Dest : 2;
u32 CAO_Dest : 2;
u32 MEDIA_Dest : 2;
u32 net_ovflow_error : 1;
u32 media_ovflow_error : 1;
u32 cai_ovflow_error : 1;
u32 cao_ovflow_error : 1;
u32 ctrl_usb_wan : 1;
u32 ctrl_sramdma : 1;
u32 ctrl_maximumfill : 1;
u32 reserved :17;
} sram_dest_reg_714;
struct {
u32 net_cnt :12;
u32 reserved1 : 4;
u32 net_addr_read : 1;
u32 reserved2 : 3;
u32 net_addr_write : 1;
u32 reserved3 :11;
} net_buf_reg_718;
struct {
u32 wan_speed_sig : 2;
u32 reserved1 : 6;
u32 wan_wait_state : 8;
u32 sram_chip : 2;
u32 sram_memmap : 2;
u32 reserved2 : 4;
u32 wan_pkt_frame : 4;
u32 reserved3 : 4;
} wan_ctrl_reg_71c;
} flexcop_ibi_value;
#endif