summaryrefslogtreecommitdiff
path: root/drivers/media/pci/ddbridge
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/pci/ddbridge')
-rw-r--r--drivers/media/pci/ddbridge/Kconfig1
-rw-r--r--drivers/media/pci/ddbridge/Makefile2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-ci.c2
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c419
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-hw.c11
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-i2c.c5
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-main.c91
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-max.c42
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-max.h1
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-mci.c551
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-mci.h156
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-regs.h4
-rw-r--r--drivers/media/pci/ddbridge/ddbridge.h50
13 files changed, 1097 insertions, 238 deletions
diff --git a/drivers/media/pci/ddbridge/Kconfig b/drivers/media/pci/ddbridge/Kconfig
index a422dde2f34a..16faef265e97 100644
--- a/drivers/media/pci/ddbridge/Kconfig
+++ b/drivers/media/pci/ddbridge/Kconfig
@@ -14,6 +14,7 @@ config DVB_DDBRIDGE
select MEDIA_TUNER_TDA18212 if MEDIA_SUBDRV_AUTOSELECT
select DVB_MXL5XX if MEDIA_SUBDRV_AUTOSELECT
select DVB_CXD2099 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_DUMMY_FE if MEDIA_SUBDRV_AUTOSELECT
---help---
Support for cards with the Digital Devices PCI express bridge:
- Octopus PCIe Bridge
diff --git a/drivers/media/pci/ddbridge/Makefile b/drivers/media/pci/ddbridge/Makefile
index 745b37d07558..9b9e35f171b7 100644
--- a/drivers/media/pci/ddbridge/Makefile
+++ b/drivers/media/pci/ddbridge/Makefile
@@ -4,7 +4,7 @@
#
ddbridge-objs := ddbridge-main.o ddbridge-core.o ddbridge-ci.o \
- ddbridge-hw.o ddbridge-i2c.o ddbridge-max.o
+ ddbridge-hw.o ddbridge-i2c.o ddbridge-max.o ddbridge-mci.o
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
diff --git a/drivers/media/pci/ddbridge/ddbridge-ci.c b/drivers/media/pci/ddbridge/ddbridge-ci.c
index a9dbc4ebf94f..cfe23d02e561 100644
--- a/drivers/media/pci/ddbridge/ddbridge-ci.c
+++ b/drivers/media/pci/ddbridge/ddbridge-ci.c
@@ -164,7 +164,7 @@ static struct dvb_ca_en50221 en_templ = {
static void ci_attach(struct ddb_port *port)
{
- struct ddb_ci *ci = NULL;
+ struct ddb_ci *ci;
ci = kzalloc(sizeof(*ci), GFP_KERNEL);
if (!ci)
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index 90687eff5909..d5b0d1eaf3ad 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -54,6 +54,7 @@
#include "stv6111.h"
#include "lnbh25.h"
#include "cxd2099.h"
+#include "dvb_dummy_fe.h"
/****************************************************************************/
@@ -68,11 +69,53 @@ module_param(adapter_alloc, int, 0444);
MODULE_PARM_DESC(adapter_alloc,
"0-one adapter per io, 1-one per tab with io, 2-one per tab, 3-one for all");
+static int ci_bitrate = 70000;
+module_param(ci_bitrate, int, 0444);
+MODULE_PARM_DESC(ci_bitrate, " Bitrate in KHz for output to CI.");
+
+static int ts_loop = -1;
+module_param(ts_loop, int, 0444);
+MODULE_PARM_DESC(ts_loop, "TS in/out test loop on port ts_loop");
+
+static int xo2_speed = 2;
+module_param(xo2_speed, int, 0444);
+MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards");
+
+#ifdef __arm__
+static int alt_dma = 1;
+#else
+static int alt_dma;
+#endif
+module_param(alt_dma, int, 0444);
+MODULE_PARM_DESC(alt_dma, "use alternative DMA buffer handling");
+
+static int no_init;
+module_param(no_init, int, 0444);
+MODULE_PARM_DESC(no_init, "do not initialize most devices");
+
+static int stv0910_single;
+module_param(stv0910_single, int, 0444);
+MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods");
+
+static int dma_buf_num = 8;
+module_param(dma_buf_num, int, 0444);
+MODULE_PARM_DESC(dma_buf_num, "Number of DMA buffers, possible values: 8-32");
+
+static int dma_buf_size = 21;
+module_param(dma_buf_size, int, 0444);
+MODULE_PARM_DESC(dma_buf_size,
+ "DMA buffer size as multiple of 128*47, possible values: 1-43");
+
+static int dummy_tuner;
+module_param(dummy_tuner, int, 0444);
+MODULE_PARM_DESC(dummy_tuner,
+ "attach dummy tuner to port 0 on Octopus V3 or Octopus Mini cards");
+
/****************************************************************************/
static DEFINE_MUTEX(redirect_lock);
-struct workqueue_struct *ddb_wq;
+static struct workqueue_struct *ddb_wq;
static struct ddb *ddbs[DDB_MAX_ADAPTER];
@@ -80,6 +123,16 @@ static struct ddb *ddbs[DDB_MAX_ADAPTER];
/****************************************************************************/
/****************************************************************************/
+struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr,
+ void (*handler)(void *), void *data)
+{
+ struct ddb_irq *irq = &dev->link[link].irq[nr];
+
+ irq->handler = handler;
+ irq->data = data;
+ return irq;
+}
+
static void ddb_set_dma_table(struct ddb_io *io)
{
struct ddb *dev = io->port->dev;
@@ -410,13 +463,11 @@ static void ddb_output_start(struct ddb_output *output)
struct ddb *dev = output->port->dev;
u32 con = 0x11c, con2 = 0;
- if (output->dma) {
- spin_lock_irq(&output->dma->lock);
- output->dma->cbuf = 0;
- output->dma->coff = 0;
- output->dma->stat = 0;
- ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma));
- }
+ spin_lock_irq(&output->dma->lock);
+ output->dma->cbuf = 0;
+ output->dma->coff = 0;
+ output->dma->stat = 0;
+ ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma));
if (output->port->input[0]->port->class == DDB_PORT_LOOP)
con = (1UL << 13) | 0x14;
@@ -429,36 +480,29 @@ static void ddb_output_start(struct ddb_output *output)
ddbwritel(dev, con, TS_CONTROL(output));
ddbwritel(dev, con2, TS_CONTROL2(output));
- if (output->dma) {
- ddbwritel(dev, output->dma->bufval,
- DMA_BUFFER_SIZE(output->dma));
- ddbwritel(dev, 0, DMA_BUFFER_ACK(output->dma));
- ddbwritel(dev, 1, DMA_BASE_READ);
- ddbwritel(dev, 7, DMA_BUFFER_CONTROL(output->dma));
- }
+ ddbwritel(dev, output->dma->bufval,
+ DMA_BUFFER_SIZE(output->dma));
+ ddbwritel(dev, 0, DMA_BUFFER_ACK(output->dma));
+ ddbwritel(dev, 1, DMA_BASE_READ);
+ ddbwritel(dev, 7, DMA_BUFFER_CONTROL(output->dma));
ddbwritel(dev, con | 1, TS_CONTROL(output));
- if (output->dma) {
- output->dma->running = 1;
- spin_unlock_irq(&output->dma->lock);
- }
+ output->dma->running = 1;
+ spin_unlock_irq(&output->dma->lock);
}
static void ddb_output_stop(struct ddb_output *output)
{
struct ddb *dev = output->port->dev;
- if (output->dma)
- spin_lock_irq(&output->dma->lock);
+ spin_lock_irq(&output->dma->lock);
ddbwritel(dev, 0, TS_CONTROL(output));
- if (output->dma) {
- ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma));
- output->dma->running = 0;
- spin_unlock_irq(&output->dma->lock);
- }
+ ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma));
+ output->dma->running = 0;
+ spin_unlock_irq(&output->dma->lock);
}
static void ddb_input_stop(struct ddb_input *input)
@@ -466,45 +510,42 @@ static void ddb_input_stop(struct ddb_input *input)
struct ddb *dev = input->port->dev;
u32 tag = DDB_LINK_TAG(input->port->lnr);
- if (input->dma)
- spin_lock_irq(&input->dma->lock);
+ spin_lock_irq(&input->dma->lock);
+
ddbwritel(dev, 0, tag | TS_CONTROL(input));
- if (input->dma) {
- ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma));
- input->dma->running = 0;
- spin_unlock_irq(&input->dma->lock);
- }
+
+ ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma));
+ input->dma->running = 0;
+ spin_unlock_irq(&input->dma->lock);
}
static void ddb_input_start(struct ddb_input *input)
{
struct ddb *dev = input->port->dev;
- if (input->dma) {
- spin_lock_irq(&input->dma->lock);
- input->dma->cbuf = 0;
- input->dma->coff = 0;
- input->dma->stat = 0;
- ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma));
- }
+ spin_lock_irq(&input->dma->lock);
+ input->dma->cbuf = 0;
+ input->dma->coff = 0;
+ input->dma->stat = 0;
+ ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma));
+
ddbwritel(dev, 0, TS_CONTROL(input));
ddbwritel(dev, 2, TS_CONTROL(input));
ddbwritel(dev, 0, TS_CONTROL(input));
- if (input->dma) {
- ddbwritel(dev, input->dma->bufval,
- DMA_BUFFER_SIZE(input->dma));
- ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma));
- ddbwritel(dev, 1, DMA_BASE_WRITE);
- ddbwritel(dev, 3, DMA_BUFFER_CONTROL(input->dma));
- }
+ ddbwritel(dev, input->dma->bufval,
+ DMA_BUFFER_SIZE(input->dma));
+ ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma));
+ ddbwritel(dev, 1, DMA_BASE_WRITE);
+ ddbwritel(dev, 3, DMA_BUFFER_CONTROL(input->dma));
ddbwritel(dev, 0x09, TS_CONTROL(input));
- if (input->dma) {
- input->dma->running = 1;
- spin_unlock_irq(&input->dma->lock);
- }
+ if (input->port->type == DDB_TUNER_DUMMY)
+ ddbwritel(dev, 0x000fff01, TS_CONTROL2(input));
+
+ input->dma->running = 1;
+ spin_unlock_irq(&input->dma->lock);
}
static void ddb_input_start_all(struct ddb_input *input)
@@ -549,12 +590,12 @@ static u32 ddb_output_free(struct ddb_output *output)
if (output->dma->cbuf != idx) {
if ((((output->dma->cbuf + 1) % output->dma->num) == idx) &&
- (output->dma->size - output->dma->coff <= 188))
+ (output->dma->size - output->dma->coff <= (2 * 188)))
return 0;
return 188;
}
diff = off - output->dma->coff;
- if (diff <= 0 || diff > 188)
+ if (diff <= 0 || diff > (2 * 188))
return 188;
return 0;
}
@@ -1142,6 +1183,7 @@ static const struct stv0910_cfg stv0910_p = {
.parallel = 1,
.rptlvl = 4,
.clk = 30000000,
+ .tsspeed = 0x28,
};
static const struct lnbh25_config lnbh25_cfg = {
@@ -1149,7 +1191,7 @@ static const struct lnbh25_config lnbh25_cfg = {
.data2_config = LNBH25_TEN
};
-static int demod_attach_stv0910(struct ddb_input *input, int type)
+static int demod_attach_stv0910(struct ddb_input *input, int type, int tsfast)
{
struct i2c_adapter *i2c = &input->port->i2c->adap;
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
@@ -1162,6 +1204,12 @@ static int demod_attach_stv0910(struct ddb_input *input, int type)
if (type)
cfg.parallel = 2;
+
+ if (tsfast) {
+ dev_info(dev, "Enabling stv0910 higher speed TS\n");
+ cfg.tsspeed = 0x10;
+ }
+
dvb->fe = dvb_attach(stv0910_attach, i2c, &cfg, (input->nr & 1));
if (!dvb->fe) {
cfg.adr = 0x6c;
@@ -1208,6 +1256,20 @@ static int tuner_attach_stv6111(struct ddb_input *input, int type)
return 0;
}
+static int demod_attach_dummy(struct ddb_input *input)
+{
+ struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
+ struct device *dev = input->port->dev->dev;
+
+ dvb->fe = dvb_attach(dvb_dummy_fe_qam_attach);
+ if (!dvb->fe) {
+ dev_err(dev, "QAM dummy attach failed!\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
static int start_feed(struct dvb_demux_feed *dvbdmxfeed)
{
struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
@@ -1383,7 +1445,25 @@ static int dvb_input_attach(struct ddb_input *input)
struct ddb_port *port = input->port;
struct dvb_adapter *adap = dvb->adap;
struct dvb_demux *dvbdemux = &dvb->demux;
- int par = 0, osc24 = 0;
+ struct ddb_ids *devids = &input->port->dev->link[input->port->lnr].ids;
+ int par = 0, osc24 = 0, tsfast = 0;
+
+ /*
+ * Determine if bridges with stv0910 demods can run with fast TS and
+ * thus support high bandwidth transponders.
+ * STV0910_PR and STV0910_P tuner types covers all relevant bridges,
+ * namely the CineS2 V7(A) and the Octopus CI S2 Pro/Advanced. All
+ * DuoFlex S2 V4(A) have type=DDB_TUNER_DVBS_STV0910 without any suffix
+ * and are limited by the serial link to the bridge, thus won't work
+ * in fast TS mode.
+ */
+ if (port->nr == 0 &&
+ (port->type == DDB_TUNER_DVBS_STV0910_PR ||
+ port->type == DDB_TUNER_DVBS_STV0910_P)) {
+ /* fast TS on port 0 requires FPGA version >= 1.7 */
+ if ((devids->hwid & 0x00ffffff) >= 0x00010007)
+ tsfast = 1;
+ }
dvb->attached = 0x01;
@@ -1440,19 +1520,19 @@ static int dvb_input_attach(struct ddb_input *input)
goto err_tuner;
break;
case DDB_TUNER_DVBS_STV0910:
- if (demod_attach_stv0910(input, 0) < 0)
+ if (demod_attach_stv0910(input, 0, tsfast) < 0)
goto err_detach;
if (tuner_attach_stv6111(input, 0) < 0)
goto err_tuner;
break;
case DDB_TUNER_DVBS_STV0910_PR:
- if (demod_attach_stv0910(input, 1) < 0)
+ if (demod_attach_stv0910(input, 1, tsfast) < 0)
goto err_detach;
if (tuner_attach_stv6111(input, 1) < 0)
goto err_tuner;
break;
case DDB_TUNER_DVBS_STV0910_P:
- if (demod_attach_stv0910(input, 0) < 0)
+ if (demod_attach_stv0910(input, 0, tsfast) < 0)
goto err_detach;
if (tuner_attach_stv6111(input, 1) < 0)
goto err_tuner;
@@ -1500,6 +1580,14 @@ static int dvb_input_attach(struct ddb_input *input)
if (tuner_attach_tda18212(input, port->type) < 0)
goto err_tuner;
break;
+ case DDB_TUNER_DUMMY:
+ if (demod_attach_dummy(input) < 0)
+ goto err_detach;
+ break;
+ case DDB_TUNER_MCI:
+ if (ddb_fe_attach_mci(input) < 0)
+ goto err_detach;
+ break;
default:
return 0;
}
@@ -1762,6 +1850,15 @@ static void ddb_port_probe(struct ddb_port *port)
/* Handle missing ports and ports without I2C */
+ if (dummy_tuner && !port->nr &&
+ dev->link[0].ids.device == 0x0005) {
+ port->name = "DUMMY";
+ port->class = DDB_PORT_TUNER;
+ port->type = DDB_TUNER_DUMMY;
+ port->type_name = "DUMMY";
+ return;
+ }
+
if (port->nr == ts_loop) {
port->name = "TS LOOP";
port->class = DDB_PORT_LOOP;
@@ -1786,6 +1883,16 @@ static void ddb_port_probe(struct ddb_port *port)
return;
}
+ if (dev->link[l].info->type == DDB_OCTOPUS_MCI) {
+ if (port->nr >= dev->link[l].info->mci)
+ return;
+ port->name = "DUAL MCI";
+ port->type_name = "MCI";
+ port->class = DDB_PORT_TUNER;
+ port->type = DDB_TUNER_MCI;
+ return;
+ }
+
if (port->nr > 1 && dev->link[l].info->type == DDB_OCTOPUS_CI) {
port->name = "CI internal";
port->type_name = "INTERNAL";
@@ -2081,39 +2188,39 @@ static void input_work(struct work_struct *work)
spin_unlock_irqrestore(&dma->lock, flags);
}
-static void input_handler(unsigned long data)
+static void input_handler(void *data)
{
struct ddb_input *input = (struct ddb_input *)data;
struct ddb_dma *dma = input->dma;
- /*
- * If there is no input connected, input_tasklet() will
- * just copy pointers and ACK. So, there is no need to go
- * through the tasklet scheduler.
- */
- if (input->redi)
- queue_work(ddb_wq, &dma->work);
- else
- input_work(&dma->work);
+ queue_work(ddb_wq, &dma->work);
}
-static void output_handler(unsigned long data)
+static void output_work(struct work_struct *work)
{
- struct ddb_output *output = (struct ddb_output *)data;
- struct ddb_dma *dma = output->dma;
+ struct ddb_dma *dma = container_of(work, struct ddb_dma, work);
+ struct ddb_output *output = (struct ddb_output *)dma->io;
struct ddb *dev = output->port->dev;
+ unsigned long flags;
- spin_lock(&dma->lock);
- if (!dma->running) {
- spin_unlock(&dma->lock);
- return;
- }
+ spin_lock_irqsave(&dma->lock, flags);
+ if (!dma->running)
+ goto unlock_exit;
dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma));
dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma));
if (output->redi)
output_ack_input(output, output->redi);
wake_up(&dma->wq);
- spin_unlock(&dma->lock);
+unlock_exit:
+ spin_unlock_irqrestore(&dma->lock, flags);
+}
+
+static void output_handler(void *data)
+{
+ struct ddb_output *output = (struct ddb_output *)data;
+ struct ddb_dma *dma = output->dma;
+
+ queue_work(ddb_wq, &dma->work);
}
/****************************************************************************/
@@ -2146,18 +2253,19 @@ static void ddb_dma_init(struct ddb_io *io, int nr, int out)
spin_lock_init(&dma->lock);
init_waitqueue_head(&dma->wq);
if (out) {
+ INIT_WORK(&dma->work, output_work);
dma->regs = rm->odma->base + rm->odma->size * nr;
dma->bufregs = rm->odma_buf->base + rm->odma_buf->size * nr;
- dma->num = OUTPUT_DMA_BUFS;
- dma->size = OUTPUT_DMA_SIZE;
- dma->div = OUTPUT_DMA_IRQ_DIV;
+ dma->num = dma_buf_num;
+ dma->size = dma_buf_size * 128 * 47;
+ dma->div = 1;
} else {
INIT_WORK(&dma->work, input_work);
dma->regs = rm->idma->base + rm->idma->size * nr;
dma->bufregs = rm->idma_buf->base + rm->idma_buf->size * nr;
- dma->num = INPUT_DMA_BUFS;
- dma->size = INPUT_DMA_SIZE;
- dma->div = INPUT_DMA_IRQ_DIV;
+ dma->num = dma_buf_num;
+ dma->size = dma_buf_size * 128 * 47;
+ dma->div = 1;
}
ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma));
dev_dbg(io->port->dev->dev, "init link %u, io %u, dma %u, dmaregs %08x bufregs %08x\n",
@@ -2190,8 +2298,7 @@ static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr)
dev_dbg(dev->dev, "init link %u, input %u, handler %u\n",
port->lnr, nr, dma_nr + base);
- dev->handler[0][dma_nr + base] = input_handler;
- dev->handler_data[0][dma_nr + base] = (unsigned long)input;
+ ddb_irq_set(dev, 0, dma_nr + base, &input_handler, input);
ddb_dma_init(input, dma_nr, 0);
}
}
@@ -2216,8 +2323,7 @@ static void ddb_output_init(struct ddb_port *port, int nr)
const struct ddb_regmap *rm0 = io_regmap(output, 0);
u32 base = rm0->irq_base_odma;
- dev->handler[0][nr + base] = output_handler;
- dev->handler_data[0][nr + base] = (unsigned long)output;
+ ddb_irq_set(dev, 0, nr + base, &output_handler, output);
ddb_dma_init(output, nr, 1);
}
}
@@ -2329,6 +2435,7 @@ void ddb_ports_init(struct ddb *dev)
break;
case DDB_OCTOPUS_MAX:
case DDB_OCTOPUS_MAX_CT:
+ case DDB_OCTOPUS_MCI:
ddb_input_init(port, 2 * i, 0, 2 * p);
ddb_input_init(port, 2 * i + 1, 1, 2 * p + 1);
break;
@@ -2361,73 +2468,62 @@ void ddb_ports_release(struct ddb *dev)
/****************************************************************************/
#define IRQ_HANDLE(_nr) \
- do { if ((s & (1UL << ((_nr) & 0x1f))) && dev->handler[0][_nr]) \
- dev->handler[0][_nr](dev->handler_data[0][_nr]); } \
+ do { if ((s & (1UL << ((_nr) & 0x1f))) && \
+ dev->link[0].irq[_nr].handler) \
+ dev->link[0].irq[_nr].handler(dev->link[0].irq[_nr].data); } \
while (0)
+#define IRQ_HANDLE_NIBBLE(_shift) { \
+ if (s & (0x0000000f << ((_shift) & 0x1f))) { \
+ IRQ_HANDLE(0 + (_shift)); \
+ IRQ_HANDLE(1 + (_shift)); \
+ IRQ_HANDLE(2 + (_shift)); \
+ IRQ_HANDLE(3 + (_shift)); \
+ } \
+}
+
+#define IRQ_HANDLE_BYTE(_shift) { \
+ if (s & (0x000000ff << ((_shift) & 0x1f))) { \
+ IRQ_HANDLE(0 + (_shift)); \
+ IRQ_HANDLE(1 + (_shift)); \
+ IRQ_HANDLE(2 + (_shift)); \
+ IRQ_HANDLE(3 + (_shift)); \
+ IRQ_HANDLE(4 + (_shift)); \
+ IRQ_HANDLE(5 + (_shift)); \
+ IRQ_HANDLE(6 + (_shift)); \
+ IRQ_HANDLE(7 + (_shift)); \
+ } \
+}
+
static void irq_handle_msg(struct ddb *dev, u32 s)
{
dev->i2c_irq++;
- IRQ_HANDLE(0);
- IRQ_HANDLE(1);
- IRQ_HANDLE(2);
- IRQ_HANDLE(3);
+ IRQ_HANDLE_NIBBLE(0);
}
static void irq_handle_io(struct ddb *dev, u32 s)
{
dev->ts_irq++;
- if ((s & 0x000000f0)) {
- IRQ_HANDLE(4);
- IRQ_HANDLE(5);
- IRQ_HANDLE(6);
- IRQ_HANDLE(7);
- }
- if ((s & 0x0000ff00)) {
- IRQ_HANDLE(8);
- IRQ_HANDLE(9);
- IRQ_HANDLE(10);
- IRQ_HANDLE(11);
- IRQ_HANDLE(12);
- IRQ_HANDLE(13);
- IRQ_HANDLE(14);
- IRQ_HANDLE(15);
- }
- if ((s & 0x00ff0000)) {
- IRQ_HANDLE(16);
- IRQ_HANDLE(17);
- IRQ_HANDLE(18);
- IRQ_HANDLE(19);
- IRQ_HANDLE(20);
- IRQ_HANDLE(21);
- IRQ_HANDLE(22);
- IRQ_HANDLE(23);
- }
- if ((s & 0xff000000)) {
- IRQ_HANDLE(24);
- IRQ_HANDLE(25);
- IRQ_HANDLE(26);
- IRQ_HANDLE(27);
- IRQ_HANDLE(28);
- IRQ_HANDLE(29);
- IRQ_HANDLE(30);
- IRQ_HANDLE(31);
- }
+ IRQ_HANDLE_NIBBLE(4);
+ IRQ_HANDLE_BYTE(8);
+ IRQ_HANDLE_BYTE(16);
+ IRQ_HANDLE_BYTE(24);
}
irqreturn_t ddb_irq_handler0(int irq, void *dev_id)
{
struct ddb *dev = (struct ddb *)dev_id;
- u32 s = ddbreadl(dev, INTERRUPT_STATUS);
+ u32 mask = 0x8fffff00;
+ u32 s = mask & ddbreadl(dev, INTERRUPT_STATUS);
+ if (!s)
+ return IRQ_NONE;
do {
if (s & 0x80000000)
return IRQ_NONE;
- if (!(s & 0xfffff00))
- return IRQ_NONE;
- ddbwritel(dev, s & 0xfffff00, INTERRUPT_ACK);
+ ddbwritel(dev, s, INTERRUPT_ACK);
irq_handle_io(dev, s);
- } while ((s = ddbreadl(dev, INTERRUPT_STATUS)));
+ } while ((s = mask & ddbreadl(dev, INTERRUPT_STATUS)));
return IRQ_HANDLED;
}
@@ -2435,16 +2531,17 @@ irqreturn_t ddb_irq_handler0(int irq, void *dev_id)
irqreturn_t ddb_irq_handler1(int irq, void *dev_id)
{
struct ddb *dev = (struct ddb *)dev_id;
- u32 s = ddbreadl(dev, INTERRUPT_STATUS);
+ u32 mask = 0x8000000f;
+ u32 s = mask & ddbreadl(dev, INTERRUPT_STATUS);
+ if (!s)
+ return IRQ_NONE;
do {
if (s & 0x80000000)
return IRQ_NONE;
- if (!(s & 0x0000f))
- return IRQ_NONE;
- ddbwritel(dev, s & 0x0000f, INTERRUPT_ACK);
+ ddbwritel(dev, s, INTERRUPT_ACK);
irq_handle_msg(dev, s);
- } while ((s = ddbreadl(dev, INTERRUPT_STATUS)));
+ } while ((s = mask & ddbreadl(dev, INTERRUPT_STATUS)));
return IRQ_HANDLED;
}
@@ -3027,7 +3124,7 @@ static struct class ddb_class = {
.devnode = ddb_devnode,
};
-int ddb_class_create(void)
+static int ddb_class_create(void)
{
ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops);
if (ddb_major < 0)
@@ -3037,7 +3134,7 @@ int ddb_class_create(void)
return 0;
}
-void ddb_class_destroy(void)
+static void ddb_class_destroy(void)
{
class_unregister(&ddb_class);
unregister_chrdev(ddb_major, DDB_NAME);
@@ -3173,7 +3270,7 @@ static void tempmon_setfan(struct ddb_link *link)
ddblwritel(link, (pwm << 8), TEMPMON_FANCONTROL);
}
-static void temp_handler(unsigned long data)
+static void temp_handler(void *data)
{
struct ddb_link *link = (struct ddb_link *)data;
@@ -3196,8 +3293,7 @@ static int tempmon_init(struct ddb_link *link, int first_time)
memcpy(link->temp_tab, temperature_table,
sizeof(temperature_table));
}
- dev->handler[l][link->info->tempmon_irq] = temp_handler;
- dev->handler_data[l][link->info->tempmon_irq] = (unsigned long)link;
+ ddb_irq_set(dev, l, link->info->tempmon_irq, temp_handler, link);
ddblwritel(link, (TEMPMON_CONTROL_OVERTEMP | TEMPMON_CONTROL_AUTOSCAN |
TEMPMON_CONTROL_INTENABLE),
TEMPMON_CONTROL);
@@ -3309,3 +3405,38 @@ void ddb_unmap(struct ddb *dev)
iounmap(dev->regs);
vfree(dev);
}
+
+int ddb_exit_ddbridge(int stage, int error)
+{
+ switch (stage) {
+ default:
+ case 2:
+ destroy_workqueue(ddb_wq);
+ /* fall-through */
+ case 1:
+ ddb_class_destroy();
+ break;
+ }
+
+ return error;
+}
+
+int ddb_init_ddbridge(void)
+{
+ if (dma_buf_num < 8)
+ dma_buf_num = 8;
+ if (dma_buf_num > 32)
+ dma_buf_num = 32;
+ if (dma_buf_size < 1)
+ dma_buf_size = 1;
+ if (dma_buf_size > 43)
+ dma_buf_size = 43;
+
+ if (ddb_class_create() < 0)
+ return -1;
+ ddb_wq = alloc_workqueue("ddbridge", 0, 0);
+ if (!ddb_wq)
+ return ddb_exit_ddbridge(1, -1);
+
+ return 0;
+}
diff --git a/drivers/media/pci/ddbridge/ddbridge-hw.c b/drivers/media/pci/ddbridge/ddbridge-hw.c
index c6d14925e2fc..1d3ee6accdd5 100644
--- a/drivers/media/pci/ddbridge/ddbridge-hw.c
+++ b/drivers/media/pci/ddbridge/ddbridge-hw.c
@@ -311,6 +311,16 @@ static const struct ddb_info ddb_s2_48 = {
.tempmon_irq = 24,
};
+static const struct ddb_info ddb_s2x_48 = {
+ .type = DDB_OCTOPUS_MCI,
+ .name = "Digital Devices MAX SX8",
+ .regmap = &octopus_map,
+ .port_num = 4,
+ .i2c_mask = 0x00,
+ .tempmon_irq = 24,
+ .mci = 4
+};
+
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
@@ -346,6 +356,7 @@ static const struct ddb_device_id ddb_device_ids[] = {
DDB_DEVID(0x0008, 0x0036, ddb_isdbt_8),
DDB_DEVID(0x0008, 0x0037, ddb_c2t2i_v0_8),
DDB_DEVID(0x0008, 0x0038, ddb_c2t2i_8),
+ DDB_DEVID(0x0009, 0x0025, ddb_s2x_48),
DDB_DEVID(0x0006, 0x0039, ddb_ctv7),
DDB_DEVID(0x0011, 0x0040, ddb_ci),
DDB_DEVID(0x0011, 0x0041, ddb_cis),
diff --git a/drivers/media/pci/ddbridge/ddbridge-i2c.c b/drivers/media/pci/ddbridge/ddbridge-i2c.c
index 82a9a0e806fc..667340c86ea7 100644
--- a/drivers/media/pci/ddbridge/ddbridge-i2c.c
+++ b/drivers/media/pci/ddbridge/ddbridge-i2c.c
@@ -147,7 +147,7 @@ void ddb_i2c_release(struct ddb *dev)
}
}
-static void i2c_handler(unsigned long priv)
+static void i2c_handler(void *priv)
{
struct ddb_i2c *i2c = (struct ddb_i2c *)priv;
@@ -210,8 +210,7 @@ int ddb_i2c_init(struct ddb *dev)
if (!(dev->link[l].info->i2c_mask & (1 << i)))
continue;
i2c = &dev->i2c[num];
- dev->handler_data[l][i + base] = (unsigned long)i2c;
- dev->handler[l][i + base] = i2c_handler;
+ ddb_irq_set(dev, l, i + base, i2c_handler, i2c);
stat = ddb_i2c_add(dev, i2c, regmap, l, i, num);
if (stat)
break;
diff --git a/drivers/media/pci/ddbridge/ddbridge-main.c b/drivers/media/pci/ddbridge/ddbridge-main.c
index 26497d6b1395..f4748cfd904b 100644
--- a/drivers/media/pci/ddbridge/ddbridge-main.c
+++ b/drivers/media/pci/ddbridge/ddbridge-main.c
@@ -55,34 +55,6 @@ MODULE_PARM_DESC(msi, "Control MSI interrupts: 0-disable (default), 1-enable");
#endif
#endif
-int ci_bitrate = 70000;
-module_param(ci_bitrate, int, 0444);
-MODULE_PARM_DESC(ci_bitrate, " Bitrate in KHz for output to CI.");
-
-int ts_loop = -1;
-module_param(ts_loop, int, 0444);
-MODULE_PARM_DESC(ts_loop, "TS in/out test loop on port ts_loop");
-
-int xo2_speed = 2;
-module_param(xo2_speed, int, 0444);
-MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards");
-
-#ifdef __arm__
-int alt_dma = 1;
-#else
-int alt_dma;
-#endif
-module_param(alt_dma, int, 0444);
-MODULE_PARM_DESC(alt_dma, "use alternative DMA buffer handling");
-
-int no_init;
-module_param(no_init, int, 0444);
-MODULE_PARM_DESC(no_init, "do not initialize most devices");
-
-int stv0910_single;
-module_param(stv0910_single, int, 0444);
-MODULE_PARM_DESC(stv0910_single, "use stv0910 cards as single demods");
-
/****************************************************************************/
/****************************************************************************/
/****************************************************************************/
@@ -93,18 +65,22 @@ static void ddb_irq_disable(struct ddb *dev)
ddbwritel(dev, 0, MSI1_ENABLE);
}
-static void ddb_irq_exit(struct ddb *dev)
+static void ddb_msi_exit(struct ddb *dev)
{
- ddb_irq_disable(dev);
- if (dev->msi == 2)
- free_irq(dev->pdev->irq + 1, dev);
- free_irq(dev->pdev->irq, dev);
#ifdef CONFIG_PCI_MSI
if (dev->msi)
- pci_disable_msi(dev->pdev);
+ pci_free_irq_vectors(dev->pdev);
#endif
}
+static void ddb_irq_exit(struct ddb *dev)
+{
+ ddb_irq_disable(dev);
+ if (dev->msi == 2)
+ free_irq(pci_irq_vector(dev->pdev, 1), dev);
+ free_irq(pci_irq_vector(dev->pdev, 0), dev);
+}
+
static void ddb_remove(struct pci_dev *pdev)
{
struct ddb *dev = (struct ddb *)pci_get_drvdata(pdev);
@@ -114,6 +90,7 @@ static void ddb_remove(struct pci_dev *pdev)
ddb_i2c_release(dev);
ddb_irq_exit(dev);
+ ddb_msi_exit(dev);
ddb_ports_release(dev);
ddb_buffers_free(dev);
@@ -128,7 +105,8 @@ static void ddb_irq_msi(struct ddb *dev, int nr)
int stat;
if (msi && pci_msi_enabled()) {
- stat = pci_alloc_irq_vectors(dev->pdev, 1, nr, PCI_IRQ_MSI);
+ stat = pci_alloc_irq_vectors(dev->pdev, 1, nr,
+ PCI_IRQ_MSI | PCI_IRQ_MSIX);
if (stat >= 1) {
dev->msi = stat;
dev_info(dev->dev, "using %d MSI interrupt(s)\n",
@@ -160,21 +138,24 @@ static int ddb_irq_init(struct ddb *dev)
if (dev->msi)
irq_flag = 0;
if (dev->msi == 2) {
- stat = request_irq(dev->pdev->irq, ddb_irq_handler0,
- irq_flag, "ddbridge", (void *)dev);
+ stat = request_irq(pci_irq_vector(dev->pdev, 0),
+ ddb_irq_handler0, irq_flag, "ddbridge",
+ (void *)dev);
if (stat < 0)
return stat;
- stat = request_irq(dev->pdev->irq + 1, ddb_irq_handler1,
- irq_flag, "ddbridge", (void *)dev);
+ stat = request_irq(pci_irq_vector(dev->pdev, 1),
+ ddb_irq_handler1, irq_flag, "ddbridge",
+ (void *)dev);
if (stat < 0) {
- free_irq(dev->pdev->irq, dev);
+ free_irq(pci_irq_vector(dev->pdev, 0), dev);
return stat;
}
} else
#endif
{
- stat = request_irq(dev->pdev->irq, ddb_irq_handler,
- irq_flag, "ddbridge", (void *)dev);
+ stat = request_irq(pci_irq_vector(dev->pdev, 0),
+ ddb_irq_handler, irq_flag, "ddbridge",
+ (void *)dev);
if (stat < 0)
return stat;
}
@@ -217,6 +198,7 @@ static int ddb_probe(struct pci_dev *pdev,
dev->link[0].ids.device = id->device;
dev->link[0].ids.subvendor = id->subvendor;
dev->link[0].ids.subdevice = pdev->subsystem_device;
+ dev->link[0].ids.devid = (id->device << 16) | id->vendor;
dev->link[0].dev = dev;
dev->link[0].info = get_ddb_info(id->vendor, id->device,
@@ -258,8 +240,7 @@ static int ddb_probe(struct pci_dev *pdev,
ddb_irq_exit(dev);
fail0:
dev_err(&pdev->dev, "fail0\n");
- if (dev->msi)
- pci_disable_msi(dev->pdev);
+ ddb_msi_exit(dev);
fail:
dev_err(&pdev->dev, "fail\n");
@@ -283,6 +264,7 @@ static const struct pci_device_id ddb_id_table[] = {
DDB_DEVICE_ANY(0x0006),
DDB_DEVICE_ANY(0x0007),
DDB_DEVICE_ANY(0x0008),
+ DDB_DEVICE_ANY(0x0009),
DDB_DEVICE_ANY(0x0011),
DDB_DEVICE_ANY(0x0012),
DDB_DEVICE_ANY(0x0013),
@@ -310,32 +292,25 @@ static struct pci_driver ddb_pci_driver = {
static __init int module_init_ddbridge(void)
{
- int stat = -1;
+ int stat;
pr_info("Digital Devices PCIE bridge driver "
DDBRIDGE_VERSION
", Copyright (C) 2010-17 Digital Devices GmbH\n");
- if (ddb_class_create() < 0)
- return -1;
- ddb_wq = create_workqueue("ddbridge");
- if (!ddb_wq)
- goto exit1;
+ stat = ddb_init_ddbridge();
+ if (stat < 0)
+ return stat;
stat = pci_register_driver(&ddb_pci_driver);
if (stat < 0)
- goto exit2;
- return stat;
-exit2:
- destroy_workqueue(ddb_wq);
-exit1:
- ddb_class_destroy();
+ ddb_exit_ddbridge(0, stat);
+
return stat;
}
static __exit void module_exit_ddbridge(void)
{
pci_unregister_driver(&ddb_pci_driver);
- destroy_workqueue(ddb_wq);
- ddb_class_destroy();
+ ddb_exit_ddbridge(0, 0);
}
module_init(module_init_ddbridge);
diff --git a/drivers/media/pci/ddbridge/ddbridge-max.c b/drivers/media/pci/ddbridge/ddbridge-max.c
index dc6b81488746..739e4b444cf4 100644
--- a/drivers/media/pci/ddbridge/ddbridge-max.c
+++ b/drivers/media/pci/ddbridge/ddbridge-max.c
@@ -33,6 +33,7 @@
#include "ddbridge.h"
#include "ddbridge-regs.h"
#include "ddbridge-io.h"
+#include "ddbridge-mci.h"
#include "ddbridge-max.h"
#include "mxl5xx.h"
@@ -452,3 +453,44 @@ int ddb_fe_attach_mxl5xx(struct ddb_input *input)
dvb->input = tuner;
return 0;
}
+
+/******************************************************************************/
+/* MAX MCI related functions */
+
+int ddb_fe_attach_mci(struct ddb_input *input)
+{
+ struct ddb *dev = input->port->dev;
+ struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
+ struct ddb_port *port = input->port;
+ struct ddb_link *link = &dev->link[port->lnr];
+ int demod, tuner;
+
+ demod = input->nr;
+ tuner = demod & 3;
+ if (fmode == 3)
+ tuner = 0;
+ dvb->fe = ddb_mci_attach(input, 0, demod, &dvb->set_input);
+ if (!dvb->fe) {
+ dev_err(dev->dev, "No MAXSX8 found!\n");
+ return -ENODEV;
+ }
+ if (!dvb->set_input) {
+ dev_err(dev->dev, "No MCI set_input function pointer!\n");
+ return -ENODEV;
+ }
+ if (input->nr < 4) {
+ lnb_command(dev, port->lnr, input->nr, LNB_CMD_INIT);
+ lnb_set_voltage(dev, port->lnr, input->nr, SEC_VOLTAGE_OFF);
+ }
+ ddb_lnb_init_fmode(dev, link, fmode);
+
+ dvb->fe->ops.set_voltage = max_set_voltage;
+ dvb->fe->ops.enable_high_lnb_voltage = max_enable_high_lnb_voltage;
+ dvb->fe->ops.set_tone = max_set_tone;
+ dvb->diseqc_send_master_cmd = dvb->fe->ops.diseqc_send_master_cmd;
+ dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd;
+ dvb->fe->ops.diseqc_send_burst = max_send_burst;
+ dvb->fe->sec_priv = input;
+ dvb->input = tuner;
+ return 0;
+}
diff --git a/drivers/media/pci/ddbridge/ddbridge-max.h b/drivers/media/pci/ddbridge/ddbridge-max.h
index bf8bf38739f6..82efc53baa94 100644
--- a/drivers/media/pci/ddbridge/ddbridge-max.h
+++ b/drivers/media/pci/ddbridge/ddbridge-max.h
@@ -25,5 +25,6 @@
int ddb_lnb_init_fmode(struct ddb *dev, struct ddb_link *link, u32 fm);
int ddb_fe_attach_mxl5xx(struct ddb_input *input);
+int ddb_fe_attach_mci(struct ddb_input *input);
#endif /* _DDBRIDGE_MAX_H */
diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.c b/drivers/media/pci/ddbridge/ddbridge-mci.c
new file mode 100644
index 000000000000..4ac634fc96e4
--- /dev/null
+++ b/drivers/media/pci/ddbridge/ddbridge-mci.c
@@ -0,0 +1,551 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * ddbridge-mci.c: Digital Devices microcode interface
+ *
+ * Copyright (C) 2017 Digital Devices GmbH
+ * Ralph Metzler <rjkm@metzlerbros.de>
+ * Marcus Metzler <mocm@metzlerbros.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#include "ddbridge.h"
+#include "ddbridge-io.h"
+#include "ddbridge-mci.h"
+
+static LIST_HEAD(mci_list);
+
+static const u32 MCLK = (1550000000 / 12);
+static const u32 MAX_DEMOD_LDPC_BITRATE = (1550000000 / 6);
+static const u32 MAX_LDPC_BITRATE = (720000000);
+
+struct mci_base {
+ struct list_head mci_list;
+ void *key;
+ struct ddb_link *link;
+ struct completion completion;
+
+ struct device *dev;
+ struct mutex tuner_lock; /* concurrent tuner access lock */
+ u8 adr;
+ struct mutex mci_lock; /* concurrent MCI access lock */
+ int count;
+
+ u8 tuner_use_count[MCI_TUNER_MAX];
+ u8 assigned_demod[MCI_DEMOD_MAX];
+ u32 used_ldpc_bitrate[MCI_DEMOD_MAX];
+ u8 demod_in_use[MCI_DEMOD_MAX];
+ u32 iq_mode;
+};
+
+struct mci {
+ struct mci_base *base;
+ struct dvb_frontend fe;
+ int nr;
+ int demod;
+ int tuner;
+ int first_time_lock;
+ int started;
+ struct mci_result signal_info;
+
+ u32 bb_mode;
+};
+
+static int mci_reset(struct mci *state)
+{
+ struct ddb_link *link = state->base->link;
+ u32 status = 0;
+ u32 timeout = 40;
+
+ ddblwritel(link, MCI_CONTROL_RESET, MCI_CONTROL);
+ ddblwritel(link, 0, MCI_CONTROL + 4); /* 1= no internal init */
+ msleep(300);
+ ddblwritel(link, 0, MCI_CONTROL);
+
+ while (1) {
+ status = ddblreadl(link, MCI_CONTROL);
+ if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY)
+ break;
+ if (--timeout == 0)
+ break;
+ msleep(50);
+ }
+ if ((status & MCI_CONTROL_READY) == 0)
+ return -1;
+ if (link->ids.device == 0x0009)
+ ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG);
+ return 0;
+}
+
+static int mci_config(struct mci *state, u32 config)
+{
+ struct ddb_link *link = state->base->link;
+
+ if (link->ids.device != 0x0009)
+ return -EINVAL;
+ ddblwritel(link, config, SX8_TSCONFIG);
+ return 0;
+}
+
+static int _mci_cmd_unlocked(struct mci *state,
+ u32 *cmd, u32 cmd_len,
+ u32 *res, u32 res_len)
+{
+ struct ddb_link *link = state->base->link;
+ u32 i, val;
+ unsigned long stat;
+
+ val = ddblreadl(link, MCI_CONTROL);
+ if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND))
+ return -EIO;
+ if (cmd && cmd_len)
+ for (i = 0; i < cmd_len; i++)
+ ddblwritel(link, cmd[i], MCI_COMMAND + i * 4);
+ val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT);
+ ddblwritel(link, val, MCI_CONTROL);
+
+ stat = wait_for_completion_timeout(&state->base->completion, HZ);
+ if (stat == 0) {
+ dev_warn(state->base->dev, "MCI-%d: MCI timeout\n", state->nr);
+ return -EIO;
+ }
+ if (res && res_len)
+ for (i = 0; i < res_len; i++)
+ res[i] = ddblreadl(link, MCI_RESULT + i * 4);
+ return 0;
+}
+
+static int mci_cmd(struct mci *state,
+ struct mci_command *command,
+ struct mci_result *result)
+{
+ int stat;
+
+ mutex_lock(&state->base->mci_lock);
+ stat = _mci_cmd_unlocked(state,
+ (u32 *)command, sizeof(*command) / sizeof(u32),
+ (u32 *)result, sizeof(*result) / sizeof(u32));
+ mutex_unlock(&state->base->mci_lock);
+ return stat;
+}
+
+static void mci_handler(void *priv)
+{
+ struct mci_base *base = (struct mci_base *)priv;
+
+ complete(&base->completion);
+}
+
+static void release(struct dvb_frontend *fe)
+{
+ struct mci *state = fe->demodulator_priv;
+
+ state->base->count--;
+ if (state->base->count == 0) {
+ list_del(&state->base->mci_list);
+ kfree(state->base);
+ }
+ kfree(state);
+}
+
+static int read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+ int stat;
+ struct mci *state = fe->demodulator_priv;
+ struct mci_command cmd;
+ struct mci_result res;
+
+ cmd.command = MCI_CMD_GETSTATUS;
+ cmd.demod = state->demod;
+ stat = mci_cmd(state, &cmd, &res);
+ if (stat)
+ return stat;
+ *status = 0x00;
+ if (res.status == SX8_DEMOD_WAIT_MATYPE)
+ *status = 0x0f;
+ if (res.status == SX8_DEMOD_LOCKED)
+ *status = 0x1f;
+ return stat;
+}
+
+static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on)
+{
+ struct mci *state = fe->demodulator_priv;
+ struct mci_command cmd;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.tuner = state->tuner;
+ cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE;
+ return mci_cmd(state, &cmd, NULL);
+}
+
+static int stop(struct dvb_frontend *fe)
+{
+ struct mci *state = fe->demodulator_priv;
+ struct mci_command cmd;
+ u32 input = state->tuner;
+
+ memset(&cmd, 0, sizeof(cmd));
+ if (state->demod != DEMOD_UNUSED) {
+ cmd.command = MCI_CMD_STOP;
+ cmd.demod = state->demod;
+ mci_cmd(state, &cmd, NULL);
+ if (state->base->iq_mode) {
+ cmd.command = MCI_CMD_STOP;
+ cmd.demod = state->demod;
+ cmd.output = 0;
+ mci_cmd(state, &cmd, NULL);
+ mci_config(state, SX8_TSCONFIG_MODE_NORMAL);
+ }
+ }
+ mutex_lock(&state->base->tuner_lock);
+ state->base->tuner_use_count[input]--;
+ if (!state->base->tuner_use_count[input])
+ mci_set_tuner(fe, input, 0);
+ if (state->demod < MCI_DEMOD_MAX)
+ state->base->demod_in_use[state->demod] = 0;
+ state->base->used_ldpc_bitrate[state->nr] = 0;
+ state->demod = DEMOD_UNUSED;
+ state->base->assigned_demod[state->nr] = DEMOD_UNUSED;
+ state->base->iq_mode = 0;
+ mutex_unlock(&state->base->tuner_lock);
+ state->started = 0;
+ return 0;
+}
+
+static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
+{
+ struct mci *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ u32 used_ldpc_bitrate = 0, free_ldpc_bitrate;
+ u32 used_demods = 0;
+ struct mci_command cmd;
+ u32 input = state->tuner;
+ u32 bits_per_symbol = 0;
+ int i, stat = 0;
+
+ if (p->symbol_rate >= (MCLK / 2))
+ flags &= ~1;
+ if ((flags & 3) == 0)
+ return -EINVAL;
+
+ if (flags & 2) {
+ u32 tmp = modmask;
+
+ bits_per_symbol = 1;
+ while (tmp & 1) {
+ tmp >>= 1;
+ bits_per_symbol++;
+ }
+ }
+
+ mutex_lock(&state->base->tuner_lock);
+ if (state->base->iq_mode) {
+ stat = -EBUSY;
+ goto unlock;
+ }
+ for (i = 0; i < MCI_DEMOD_MAX; i++) {
+ used_ldpc_bitrate += state->base->used_ldpc_bitrate[i];
+ if (state->base->demod_in_use[i])
+ used_demods++;
+ }
+ if (used_ldpc_bitrate >= MAX_LDPC_BITRATE ||
+ ((ts_config & SX8_TSCONFIG_MODE_MASK) >
+ SX8_TSCONFIG_MODE_NORMAL && used_demods > 0)) {
+ stat = -EBUSY;
+ goto unlock;
+ }
+ free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate;
+ if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE)
+ free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE;
+
+ while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate)
+ bits_per_symbol--;
+
+ if (bits_per_symbol < 2) {
+ stat = -EBUSY;
+ goto unlock;
+ }
+ i = (p->symbol_rate > (MCLK / 2)) ? 3 : 7;
+ while (i >= 0 && state->base->demod_in_use[i])
+ i--;
+ if (i < 0) {
+ stat = -EBUSY;
+ goto unlock;
+ }
+ state->base->demod_in_use[i] = 1;
+ state->base->used_ldpc_bitrate[state->nr] = p->symbol_rate
+ * bits_per_symbol;
+ state->demod = i;
+ state->base->assigned_demod[state->nr] = i;
+
+ if (!state->base->tuner_use_count[input])
+ mci_set_tuner(fe, input, 1);
+ state->base->tuner_use_count[input]++;
+ state->base->iq_mode = (ts_config > 1);
+unlock:
+ mutex_unlock(&state->base->tuner_lock);
+ if (stat)
+ return stat;
+ memset(&cmd, 0, sizeof(cmd));
+
+ if (state->base->iq_mode) {
+ cmd.command = SX8_CMD_SELECT_IQOUT;
+ cmd.demod = state->demod;
+ cmd.output = 0;
+ mci_cmd(state, &cmd, NULL);
+ mci_config(state, ts_config);
+ }
+ if (p->stream_id != NO_STREAM_ID_FILTER && p->stream_id != 0x80000000)
+ flags |= 0x80;
+ dev_dbg(state->base->dev, "MCI-%d: tuner=%d demod=%d\n",
+ state->nr, state->tuner, state->demod);
+ cmd.command = MCI_CMD_SEARCH_DVBS;
+ cmd.dvbs2_search.flags = flags;
+ cmd.dvbs2_search.s2_modulation_mask =
+ modmask & ((1 << (bits_per_symbol - 1)) - 1);
+ cmd.dvbs2_search.retry = 2;
+ cmd.dvbs2_search.frequency = p->frequency * 1000;
+ cmd.dvbs2_search.symbol_rate = p->symbol_rate;
+ cmd.dvbs2_search.scrambling_sequence_index =
+ p->scrambling_sequence_index;
+ cmd.dvbs2_search.input_stream_id =
+ (p->stream_id != NO_STREAM_ID_FILTER) ? p->stream_id : 0;
+ cmd.tuner = state->tuner;
+ cmd.demod = state->demod;
+ cmd.output = state->nr;
+ if (p->stream_id == 0x80000000)
+ cmd.output |= 0x80;
+ stat = mci_cmd(state, &cmd, NULL);
+ if (stat)
+ stop(fe);
+ return stat;
+}
+
+static int start_iq(struct dvb_frontend *fe, u32 ts_config)
+{
+ struct mci *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ u32 used_demods = 0;
+ struct mci_command cmd;
+ u32 input = state->tuner;
+ int i, stat = 0;
+
+ mutex_lock(&state->base->tuner_lock);
+ if (state->base->iq_mode) {
+ stat = -EBUSY;
+ goto unlock;
+ }
+ for (i = 0; i < MCI_DEMOD_MAX; i++)
+ if (state->base->demod_in_use[i])
+ used_demods++;
+ if (used_demods > 0) {
+ stat = -EBUSY;
+ goto unlock;
+ }
+ state->demod = 0;
+ state->base->assigned_demod[state->nr] = 0;
+ if (!state->base->tuner_use_count[input])
+ mci_set_tuner(fe, input, 1);
+ state->base->tuner_use_count[input]++;
+ state->base->iq_mode = (ts_config > 1);
+unlock:
+ mutex_unlock(&state->base->tuner_lock);
+ if (stat)
+ return stat;
+
+ memset(&cmd, 0, sizeof(cmd));
+ cmd.command = SX8_CMD_START_IQ;
+ cmd.dvbs2_search.frequency = p->frequency * 1000;
+ cmd.dvbs2_search.symbol_rate = p->symbol_rate;
+ cmd.tuner = state->tuner;
+ cmd.demod = state->demod;
+ cmd.output = 7;
+ mci_config(state, ts_config);
+ stat = mci_cmd(state, &cmd, NULL);
+ if (stat)
+ stop(fe);
+ return stat;
+}
+
+static int set_parameters(struct dvb_frontend *fe)
+{
+ int stat = 0;
+ struct mci *state = fe->demodulator_priv;
+ struct dtv_frontend_properties *p = &fe->dtv_property_cache;
+ u32 ts_config, iq_mode = 0, isi;
+
+ if (state->started)
+ stop(fe);
+
+ isi = p->stream_id;
+ if (isi != NO_STREAM_ID_FILTER)
+ iq_mode = (isi & 0x30000000) >> 28;
+
+ switch (iq_mode) {
+ case 1:
+ ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
+ break;
+ case 2:
+ ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
+ break;
+ default:
+ ts_config = SX8_TSCONFIG_MODE_NORMAL;
+ break;
+ }
+
+ if (iq_mode != 2) {
+ u32 flags = 3;
+ u32 mask = 3;
+
+ if (p->modulation == APSK_16 ||
+ p->modulation == APSK_32) {
+ flags = 2;
+ mask = 15;
+ }
+ stat = start(fe, flags, mask, ts_config);
+ } else {
+ stat = start_iq(fe, ts_config);
+ }
+
+ if (!stat) {
+ state->started = 1;
+ state->first_time_lock = 1;
+ state->signal_info.status = SX8_DEMOD_WAIT_SIGNAL;
+ }
+
+ return stat;
+}
+
+static int tune(struct dvb_frontend *fe, bool re_tune,
+ unsigned int mode_flags,
+ unsigned int *delay, enum fe_status *status)
+{
+ int r;
+
+ if (re_tune) {
+ r = set_parameters(fe);
+ if (r)
+ return r;
+ }
+ r = read_status(fe, status);
+ if (r)
+ return r;
+
+ if (*status & FE_HAS_LOCK)
+ return 0;
+ *delay = HZ / 10;
+ return 0;
+}
+
+static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_HW;
+}
+
+static int set_input(struct dvb_frontend *fe, int input)
+{
+ struct mci *state = fe->demodulator_priv;
+
+ state->tuner = input;
+ dev_dbg(state->base->dev, "MCI-%d: input=%d\n", state->nr, input);
+ return 0;
+}
+
+static struct dvb_frontend_ops mci_ops = {
+ .delsys = { SYS_DVBS, SYS_DVBS2 },
+ .info = {
+ .name = "Digital Devices MaxSX8 MCI DVB-S/S2/S2X",
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 0,
+ .frequency_tolerance = 0,
+ .symbol_rate_min = 100000,
+ .symbol_rate_max = 100000000,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_2G_MODULATION |
+ FE_CAN_MULTISTREAM,
+ },
+ .get_frontend_algo = get_algo,
+ .tune = tune,
+ .release = release,
+ .read_status = read_status,
+};
+
+static struct mci_base *match_base(void *key)
+{
+ struct mci_base *p;
+
+ list_for_each_entry(p, &mci_list, mci_list)
+ if (p->key == key)
+ return p;
+ return NULL;
+}
+
+static int probe(struct mci *state)
+{
+ mci_reset(state);
+ return 0;
+}
+
+struct dvb_frontend
+*ddb_mci_attach(struct ddb_input *input,
+ int mci_type, int nr,
+ int (**fn_set_input)(struct dvb_frontend *fe, int input))
+{
+ struct ddb_port *port = input->port;
+ struct ddb *dev = port->dev;
+ struct ddb_link *link = &dev->link[port->lnr];
+ struct mci_base *base;
+ struct mci *state;
+ void *key = mci_type ? (void *)port : (void *)link;
+
+ state = kzalloc(sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ base = match_base(key);
+ if (base) {
+ base->count++;
+ state->base = base;
+ } else {
+ base = kzalloc(sizeof(*base), GFP_KERNEL);
+ if (!base)
+ goto fail;
+ base->key = key;
+ base->count = 1;
+ base->link = link;
+ base->dev = dev->dev;
+ mutex_init(&base->mci_lock);
+ mutex_init(&base->tuner_lock);
+ ddb_irq_set(dev, link->nr, 0, mci_handler, base);
+ init_completion(&base->completion);
+ state->base = base;
+ if (probe(state) < 0) {
+ kfree(base);
+ goto fail;
+ }
+ list_add(&base->mci_list, &mci_list);
+ }
+ state->fe.ops = mci_ops;
+ state->fe.demodulator_priv = state;
+ state->nr = nr;
+ *fn_set_input = set_input;
+
+ state->tuner = nr;
+ state->demod = nr;
+
+ return &state->fe;
+fail:
+ kfree(state);
+ return NULL;
+}
diff --git a/drivers/media/pci/ddbridge/ddbridge-mci.h b/drivers/media/pci/ddbridge/ddbridge-mci.h
new file mode 100644
index 000000000000..209cc2b92dff
--- /dev/null
+++ b/drivers/media/pci/ddbridge/ddbridge-mci.h
@@ -0,0 +1,156 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * ddbridge-mci.h: Digital Devices micro code interface
+ *
+ * Copyright (C) 2017 Digital Devices GmbH
+ * Marcus Metzler <mocm@metzlerbros.de>
+ * Ralph Metzler <rjkm@metzlerbros.de>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 only, as published by the Free Software Foundation.
+ *
+ * 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.
+ */
+
+#ifndef _DDBRIDGE_MCI_H_
+#define _DDBRIDGE_MCI_H_
+
+#define MCI_DEMOD_MAX 8
+#define MCI_TUNER_MAX 4
+#define DEMOD_UNUSED (0xFF)
+
+#define MCI_CONTROL (0x500)
+#define MCI_COMMAND (0x600)
+#define MCI_RESULT (0x680)
+
+#define MCI_COMMAND_SIZE (0x80)
+#define MCI_RESULT_SIZE (0x80)
+
+#define MCI_CONTROL_START_COMMAND (0x00000001)
+#define MCI_CONTROL_ENABLE_DONE_INTERRUPT (0x00000002)
+#define MCI_CONTROL_RESET (0x00008000)
+#define MCI_CONTROL_READY (0x00010000)
+
+#define SX8_TSCONFIG (0x280)
+
+#define SX8_TSCONFIG_MODE_MASK (0x00000003)
+#define SX8_TSCONFIG_MODE_OFF (0x00000000)
+#define SX8_TSCONFIG_MODE_NORMAL (0x00000001)
+#define SX8_TSCONFIG_MODE_IQ (0x00000003)
+
+#define SX8_TSCONFIG_TSHEADER (0x00000004)
+#define SX8_TSCONFIG_BURST (0x00000008)
+
+#define SX8_TSCONFIG_BURSTSIZE_MASK (0x00000030)
+#define SX8_TSCONFIG_BURSTSIZE_2K (0x00000000)
+#define SX8_TSCONFIG_BURSTSIZE_4K (0x00000010)
+#define SX8_TSCONFIG_BURSTSIZE_8K (0x00000020)
+#define SX8_TSCONFIG_BURSTSIZE_16K (0x00000030)
+
+#define SX8_DEMOD_STOPPED (0)
+#define SX8_DEMOD_IQ_MODE (1)
+#define SX8_DEMOD_WAIT_SIGNAL (2)
+#define SX8_DEMOD_WAIT_MATYPE (3)
+#define SX8_DEMOD_TIMEOUT (14)
+#define SX8_DEMOD_LOCKED (15)
+
+#define MCI_CMD_STOP (0x01)
+#define MCI_CMD_GETSTATUS (0x02)
+#define MCI_CMD_GETSIGNALINFO (0x03)
+#define MCI_CMD_RFPOWER (0x04)
+
+#define MCI_CMD_SEARCH_DVBS (0x10)
+
+#define MCI_CMD_GET_IQSYMBOL (0x30)
+
+#define SX8_CMD_INPUT_ENABLE (0x40)
+#define SX8_CMD_INPUT_DISABLE (0x41)
+#define SX8_CMD_START_IQ (0x42)
+#define SX8_CMD_STOP_IQ (0x43)
+#define SX8_CMD_SELECT_IQOUT (0x44)
+#define SX8_CMD_SELECT_TSOUT (0x45)
+
+#define SX8_ERROR_UNSUPPORTED (0x80)
+
+#define SX8_SUCCESS(status) (status < SX8_ERROR_UNSUPPORTED)
+
+#define SX8_CMD_DIAG_READ8 (0xE0)
+#define SX8_CMD_DIAG_READ32 (0xE1)
+#define SX8_CMD_DIAG_WRITE8 (0xE2)
+#define SX8_CMD_DIAG_WRITE32 (0xE3)
+
+#define SX8_CMD_DIAG_READRF (0xE8)
+#define SX8_CMD_DIAG_WRITERF (0xE9)
+
+struct mci_command {
+ union {
+ u32 command_word;
+ struct {
+ u8 command;
+ u8 tuner;
+ u8 demod;
+ u8 output;
+ };
+ };
+ union {
+ u32 params[31];
+ struct {
+ u8 flags;
+ u8 s2_modulation_mask;
+ u8 rsvd1;
+ u8 retry;
+ u32 frequency;
+ u32 symbol_rate;
+ u8 input_stream_id;
+ u8 rsvd2[3];
+ u32 scrambling_sequence_index;
+ } dvbs2_search;
+ };
+};
+
+struct mci_result {
+ union {
+ u32 status_word;
+ struct {
+ u8 status;
+ u8 rsvd;
+ u16 time;
+ };
+ };
+ union {
+ u32 result[27];
+ struct {
+ u8 standard;
+ /* puncture rate for DVB-S */
+ u8 pls_code;
+ /* 7-6: rolloff, 5-2: rsrvd, 1:short, 0:pilots */
+ u8 roll_off;
+ u8 rsvd;
+ u32 frequency;
+ u32 symbol_rate;
+ s16 channel_power;
+ s16 band_power;
+ s16 signal_to_noise;
+ s16 rsvd2;
+ u32 packet_errors;
+ u32 ber_numerator;
+ u32 ber_denominator;
+ } dvbs2_signal_info;
+ struct {
+ u8 i_symbol;
+ u8 q_symbol;
+ } dvbs2_signal_iq;
+ };
+ u32 version[4];
+};
+
+struct dvb_frontend
+*ddb_mci_attach(struct ddb_input *input,
+ int mci_type, int nr,
+ int (**fn_set_input)(struct dvb_frontend *fe, int input));
+
+#endif /* _DDBRIDGE_MCI_H_ */
diff --git a/drivers/media/pci/ddbridge/ddbridge-regs.h b/drivers/media/pci/ddbridge/ddbridge-regs.h
index 23d74ff83fe4..b978b5991940 100644
--- a/drivers/media/pci/ddbridge/ddbridge-regs.h
+++ b/drivers/media/pci/ddbridge/ddbridge-regs.h
@@ -17,6 +17,9 @@
* http://www.gnu.org/copyleft/gpl.html
*/
+#ifndef __DDBRIDGE_REGS_H__
+#define __DDBRIDGE_REGS_H__
+
/* ------------------------------------------------------------------------- */
/* SPI Controller */
@@ -154,3 +157,4 @@
#define LNB_BUF_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10)
#define LNB_BUF_WRITE(i) (LNB_BASE + (i) * 0x20 + 0x14)
+#endif /* __DDBRIDGE_REGS_H__ */
diff --git a/drivers/media/pci/ddbridge/ddbridge.h b/drivers/media/pci/ddbridge/ddbridge.h
index f223dc6c9963..a66b1125cc74 100644
--- a/drivers/media/pci/ddbridge/ddbridge.h
+++ b/drivers/media/pci/ddbridge/ddbridge.h
@@ -63,7 +63,7 @@
#include <media/dvb_ca_en50221.h>
#include <media/dvb_net.h>
-#define DDBRIDGE_VERSION "0.9.32-integrated"
+#define DDBRIDGE_VERSION "0.9.33-integrated"
#define DDB_MAX_I2C 32
#define DDB_MAX_PORT 32
@@ -112,11 +112,12 @@ struct ddb_ids {
struct ddb_info {
int type;
-#define DDB_NONE 0
-#define DDB_OCTOPUS 1
-#define DDB_OCTOPUS_CI 2
-#define DDB_OCTOPUS_MAX 5
+#define DDB_NONE 0
+#define DDB_OCTOPUS 1
+#define DDB_OCTOPUS_CI 2
+#define DDB_OCTOPUS_MAX 5
#define DDB_OCTOPUS_MAX_CT 6
+#define DDB_OCTOPUS_MCI 9
char *name;
u32 i2c_mask;
u8 port_num;
@@ -133,23 +134,12 @@ struct ddb_info {
#define TS_QUIRK_REVERSED 2
#define TS_QUIRK_ALT_OSC 8
u32 tempmon_irq;
+ u8 mci;
const struct ddb_regmap *regmap;
};
-/* DMA_SIZE MUST be smaller than 256k and
- * MUST be divisible by 188 and 128 !!!
- */
-
#define DMA_MAX_BUFS 32 /* hardware table limit */
-#define INPUT_DMA_BUFS 8
-#define INPUT_DMA_SIZE (128 * 47 * 21)
-#define INPUT_DMA_IRQ_DIV 1
-
-#define OUTPUT_DMA_BUFS 8
-#define OUTPUT_DMA_SIZE (128 * 47 * 21)
-#define OUTPUT_DMA_IRQ_DIV 1
-
struct ddb;
struct ddb_port;
@@ -248,6 +238,7 @@ struct ddb_port {
char *name;
char *type_name;
u32 type;
+#define DDB_TUNER_DUMMY 0xffffffff
#define DDB_TUNER_NONE 0
#define DDB_TUNER_DVBS_ST 1
#define DDB_TUNER_DVBS_ST_AA 2
@@ -264,6 +255,7 @@ struct ddb_port {
#define DDB_CI_EXTERNAL_XO2_B 13
#define DDB_TUNER_DVBS_STV0910_PR 14
#define DDB_TUNER_DVBC2T2I_SONY_P 15
+#define DDB_TUNER_MCI 16
#define DDB_TUNER_XO2 32
#define DDB_TUNER_DVBS_STV0910 (DDB_TUNER_XO2 + 0)
@@ -305,6 +297,11 @@ struct ddb_lnb {
u32 fmode;
};
+struct ddb_irq {
+ void (*handler)(void *);
+ void *data;
+};
+
struct ddb_link {
struct ddb *dev;
const struct ddb_info *info;
@@ -319,6 +316,7 @@ struct ddb_link {
spinlock_t temp_lock; /* lock temp chip access */
int overtemperature_error;
u8 temp_tab[11];
+ struct ddb_irq irq[256];
};
struct ddb {
@@ -343,9 +341,6 @@ struct ddb {
struct ddb_dma idma[DDB_MAX_INPUT];
struct ddb_dma odma[DDB_MAX_OUTPUT];
- void (*handler[4][256])(unsigned long);
- unsigned long handler_data[4][256];
-
struct device *ddb_dev;
u32 ddb_dev_users;
u32 nr;
@@ -368,16 +363,9 @@ int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
/****************************************************************************/
-/* ddbridge-main.c (modparams) */
-extern int ci_bitrate;
-extern int ts_loop;
-extern int xo2_speed;
-extern int alt_dma;
-extern int no_init;
-extern int stv0910_single;
-extern struct workqueue_struct *ddb_wq;
-
/* ddbridge-core.c */
+struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr,
+ void (*handler)(void *), void *data);
void ddb_ports_detach(struct ddb *dev);
void ddb_ports_release(struct ddb *dev);
void ddb_buffers_free(struct ddb *dev);
@@ -389,9 +377,9 @@ void ddb_ports_init(struct ddb *dev);
int ddb_buffers_alloc(struct ddb *dev);
int ddb_ports_attach(struct ddb *dev);
int ddb_device_create(struct ddb *dev);
-int ddb_class_create(void);
-void ddb_class_destroy(void);
int ddb_init(struct ddb *dev);
void ddb_unmap(struct ddb *dev);
+int ddb_exit_ddbridge(int stage, int error);
+int ddb_init_ddbridge(void);
#endif /* DDBRIDGE_H */