From 9279ae0f9807f7b4bd5638e6fc241caeb71d8360 Mon Sep 17 00:00:00 2001 From: Stephan Raue Date: Sun, 20 Jan 2013 02:08:51 +0100 Subject: [PATCH] linux: update and move ngene/octopus patch Signed-off-by: Stephan Raue --- .../linux-221-ngene-octopus.patch} | 6056 ++++++++--------- 1 file changed, 3021 insertions(+), 3035 deletions(-) rename packages/linux/patches/{to.backport/linux-3.7.2-221-ngene-octopus.patch => 3.7.3/linux-221-ngene-octopus.patch} (97%) diff --git a/packages/linux/patches/to.backport/linux-3.7.2-221-ngene-octopus.patch b/packages/linux/patches/3.7.3/linux-221-ngene-octopus.patch similarity index 97% rename from packages/linux/patches/to.backport/linux-3.7.2-221-ngene-octopus.patch rename to packages/linux/patches/3.7.3/linux-221-ngene-octopus.patch index 1925a452a3..7da71241c9 100644 --- a/packages/linux/patches/to.backport/linux-3.7.2-221-ngene-octopus.patch +++ b/packages/linux/patches/3.7.3/linux-221-ngene-octopus.patch @@ -1,2948 +1,14 @@ -diff -Naur linux-3.6.8/drivers/media/dvb/ddbridge/ddbridge-core.c linux-3.6.8.patch/drivers/media/dvb/ddbridge/ddbridge-core.c ---- linux-3.6.8/drivers/media/dvb/ddbridge/ddbridge-core.c 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ddbridge/ddbridge-core.c 2012-12-03 08:41:17.000000000 +0100 -@@ -31,11 +31,11 @@ - #include - #include - #include -+#include - #include - #include - #include - #include "ddbridge.h" -- - #include "ddbridge-regs.h" - - #include "tda18271c2dd.h" -@@ -43,14 +43,60 @@ - #include "stv090x.h" - #include "lnbh24.h" - #include "drxk.h" -+#if 0 -+#include "stv0367.h" -+#else -+#include "stv0367dd.h" -+#endif -+#if 0 -+#include "tda18212.h" -+#else -+#include "tda18212dd.h" -+#endif -+ -+static int adapter_alloc; -+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 ts_loop = -1; -+module_param(ts_loop, int, 0444); -+MODULE_PARM_DESC(ts_loop, "TS in/out on port ts_loop"); - - DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); - -+static struct ddb *ddbs[32]; -+ - /* MSI had problems with lost interrupts, fixed but needs testing */ --#undef CONFIG_PCI_MSI -+/* #undef CONFIG_PCI_MSI */ -+ -+/******************************************************************************/ -+ -+static inline void ddbwritel(struct ddb *dev, u32 val, u32 adr) -+{ -+ writel(val, (char *) (dev->regs+(adr))); -+} -+ -+static inline u32 ddbreadl(struct ddb *dev, u32 adr) -+{ -+ return readl((char *) (dev->regs+(adr))); -+} -+ -+#define ddbcpyto(_dev, _adr, _src, _count) memcpy_toio((char *) \ -+ (_dev->regs + (_adr)), (_src), (_count)) -+ -+#define ddbcpyfrom(_dev, _dst, _adr, _count) memcpy_fromio((_dst), (char *) \ -+ (_dev->regs + (_adr)), (_count)) -+ - - /******************************************************************************/ - -+static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) -+{ -+ struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len}; -+ -+ return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; -+} -+ - static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) - { - struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, -@@ -58,10 +104,31 @@ - return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; - } - -+static int i2c_read_regs(struct i2c_adapter *adapter, -+ u8 adr, u8 reg, u8 *val, u8 len) -+{ -+ struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, -+ .buf = ®, .len = 1}, -+ {.addr = adr, .flags = I2C_M_RD, -+ .buf = val, .len = len } }; -+ return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -+} -+ -+static int i2c_read_regs16(struct i2c_adapter *adapter, -+ u8 adr, u16 reg, u8 *val, u8 len) -+{ -+ u8 reg16[2] = { reg >> 8, reg }; -+ struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, -+ .buf = (u8 *)®16, .len = 2}, -+ {.addr = adr, .flags = I2C_M_RD, -+ .buf = val, .len = len } }; -+ return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -+} -+ - static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) - { - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, -- .buf = ®, .len = 1 }, -+ .buf = ®, .len = 1}, - {.addr = adr, .flags = I2C_M_RD, - .buf = val, .len = 1 } }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; -@@ -70,14 +137,22 @@ - static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, - u16 reg, u8 *val) - { -- u8 msg[2] = {reg>>8, reg&0xff}; -+ u8 msg[2] = {reg >> 8, reg & 0xff}; - struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, - .buf = msg, .len = 2}, - {.addr = adr, .flags = I2C_M_RD, -- .buf = val, .len = 1} }; -+ .buf = val, .len = 1 } }; - return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; - } - -+static int i2c_write_reg16(struct i2c_adapter *adap, u8 adr, -+ u16 reg, u8 val) -+{ -+ u8 msg[3] = {reg >> 8, reg & 0xff, val}; -+ -+ return i2c_write(adap, adr, msg, 3); -+} -+ - static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) - { - struct ddb *dev = i2c->dev; -@@ -85,18 +160,18 @@ - u32 val; - - i2c->done = 0; -- ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND); -+ ddbwritel(dev, (adr << 9) | cmd, i2c->regs + I2C_COMMAND); - stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ); - if (stat <= 0) { - printk(KERN_ERR "I2C timeout\n"); - { /* MSI debugging*/ -- u32 istat = ddbreadl(INTERRUPT_STATUS); -+ u32 istat = ddbreadl(dev, INTERRUPT_STATUS); - printk(KERN_ERR "IRS %08x\n", istat); -- ddbwritel(istat, INTERRUPT_ACK); -+ ddbwritel(dev, istat, INTERRUPT_ACK); - } - return -EIO; - } -- val = ddbreadl(i2c->regs+I2C_COMMAND); -+ val = ddbreadl(dev, i2c->regs+I2C_COMMAND); - if (val & 0x70000) - return -EIO; - return 0; -@@ -105,7 +180,7 @@ - static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, - struct i2c_msg msg[], int num) - { -- struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter); -+ struct ddb_i2c *i2c = (struct ddb_i2c *) i2c_get_adapdata(adapter); - struct ddb *dev = i2c->dev; - u8 addr = 0; - -@@ -116,8 +191,8 @@ - !(msg[0].flags & I2C_M_RD)) { - memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf, - msg[0].buf, msg[0].len); -- ddbwritel(msg[0].len|(msg[1].len << 16), -- i2c->regs+I2C_TASKLENGTH); -+ ddbwritel(dev, msg[0].len|(msg[1].len << 16), -+ i2c->regs + I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 1)) { - memcpy_fromio(msg[1].buf, - dev->regs + I2C_TASKMEM_BASE + i2c->rbuf, -@@ -125,17 +200,16 @@ - return num; - } - } -- - if (num == 1 && !(msg[0].flags & I2C_M_RD)) { -- ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len); -- ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH); -+ ddbcpyto(dev, I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len); -+ ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 2)) - return num; - } - if (num == 1 && (msg[0].flags & I2C_M_RD)) { -- ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH); -+ ddbwritel(dev, msg[0].len << 16, i2c->regs + I2C_TASKLENGTH); - if (!ddb_i2c_cmd(i2c, addr, 3)) { -- ddbcpyfrom(msg[0].buf, -+ ddbcpyfrom(dev, msg[0].buf, - I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len); - return num; - } -@@ -160,7 +234,7 @@ - struct ddb_i2c *i2c; - struct i2c_adapter *adap; - -- for (i = 0; i < dev->info->port_num; i++) { -+ for (i = 0; i < dev->info->i2c_num; i++) { - i2c = &dev->i2c[i]; - adap = &i2c->adap; - i2c_del_adapter(adap); -@@ -173,15 +247,15 @@ - struct ddb_i2c *i2c; - struct i2c_adapter *adap; - -- for (i = 0; i < dev->info->port_num; i++) { -+ for (i = 0; i < dev->info->i2c_num; i++) { - i2c = &dev->i2c[i]; - i2c->dev = dev; - i2c->nr = i; - i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4); - i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8); - i2c->regs = 0x80 + i * 0x20; -- ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING); -- ddbwritel((i2c->rbuf << 16) | i2c->wbuf, -+ ddbwritel(dev, I2C_SPEED_100, i2c->regs + I2C_TIMING); -+ ddbwritel(dev, (i2c->rbuf << 16) | i2c->wbuf, - i2c->regs + I2C_TASKADDRESS); - init_waitqueue_head(&i2c->wq); - -@@ -216,69 +290,94 @@ - /******************************************************************************/ - /******************************************************************************/ - --#if 0 --static void set_table(struct ddb *dev, u32 off, -- dma_addr_t *pbuf, u32 num) -+static void ddb_set_dma_table(struct ddb *dev, struct ddb_dma *dma) - { - u32 i, base; - u64 mem; - -- base = DMA_BASE_ADDRESS_TABLE + off; -- for (i = 0; i < num; i++) { -- mem = pbuf[i]; -- ddbwritel(mem & 0xffffffff, base + i * 8); -- ddbwritel(mem >> 32, base + i * 8 + 4); -+ if (!dma) -+ return; -+ base = DMA_BASE_ADDRESS_TABLE + dma->nr * 0x100; -+ for (i = 0; i < dma->num; i++) { -+ mem = dma->pbuf[i]; -+ ddbwritel(dev, mem & 0xffffffff, base + i * 8); -+ ddbwritel(dev, mem >> 32, base + i * 8 + 4); - } -+ dma->bufreg = (dma->div << 16) | -+ ((dma->num & 0x1f) << 11) | -+ ((dma->size >> 7) & 0x7ff); - } --#endif - --static void ddb_address_table(struct ddb *dev) -+static void ddb_set_dma_tables(struct ddb *dev) - { -- u32 i, j, base; -- u64 mem; -- dma_addr_t *pbuf; -+ u32 i; - -- for (i = 0; i < dev->info->port_num * 2; i++) { -- base = DMA_BASE_ADDRESS_TABLE + i * 0x100; -- pbuf = dev->input[i].pbuf; -- for (j = 0; j < dev->input[i].dma_buf_num; j++) { -- mem = pbuf[j]; -- ddbwritel(mem & 0xffffffff, base + j * 8); -- ddbwritel(mem >> 32, base + j * 8 + 4); -- } -- } -- for (i = 0; i < dev->info->port_num; i++) { -- base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100; -- pbuf = dev->output[i].pbuf; -- for (j = 0; j < dev->output[i].dma_buf_num; j++) { -- mem = pbuf[j]; -- ddbwritel(mem & 0xffffffff, base + j * 8); -- ddbwritel(mem >> 32, base + j * 8 + 4); -- } -- } -+ for (i = 0; i < dev->info->port_num * 2; i++) -+ ddb_set_dma_table(dev, dev->input[i].dma); -+ for (i = 0; i < dev->info->port_num; i++) -+ ddb_set_dma_table(dev, dev->output[i].dma); - } - --static void io_free(struct pci_dev *pdev, u8 **vbuf, -- dma_addr_t *pbuf, u32 size, int num) -+static void dma_free(struct pci_dev *pdev, struct ddb_dma *dma) - { - int i; - -- for (i = 0; i < num; i++) { -- if (vbuf[i]) { -- pci_free_consistent(pdev, size, vbuf[i], pbuf[i]); -- vbuf[i] = 0; -+ if (!dma) -+ return; -+ for (i = 0; i < dma->num; i++) { -+ if (dma->vbuf[i]) { -+ pci_free_consistent(pdev, dma->size, -+ dma->vbuf[i], dma->pbuf[i]); -+ dma->vbuf[i] = 0; - } - } - } - --static int io_alloc(struct pci_dev *pdev, u8 **vbuf, -- dma_addr_t *pbuf, u32 size, int num) -+static void ddb_redirect_dma(struct ddb *dev, -+ struct ddb_dma *sdma, -+ struct ddb_dma *ddma) -+{ -+ u32 i, base; -+ u64 mem; -+ -+ sdma->bufreg = ddma->bufreg; -+ base = DMA_BASE_ADDRESS_TABLE + sdma->nr * 0x100; -+ for (i = 0; i < ddma->num; i++) { -+ mem = ddma->pbuf[i]; -+ ddbwritel(dev, mem & 0xffffffff, base + i * 8); -+ ddbwritel(dev, mem >> 32, base + i * 8 + 4); -+ } -+} -+ -+static void ddb_unredirect(struct ddb_port *port) -+{ -+ struct ddb_input *ored, *ired; -+ -+ ored = port->output->redirect; -+ ired = port->input[0]->redirect; -+ -+ if (!ored || !ired) -+ return; -+ if (ired->port->output->redirect == port->input[0]) { -+ ired->port->output->redirect = ored; -+ ddb_set_dma_table(port->dev, port->input[0]->dma); -+ ddb_redirect_dma(ored->port->dev, ored->dma, ired->port->output->dma); -+ } else -+ ddb_set_dma_table(ored->port->dev, ored->dma); -+ ored->redirect = ired; -+ port->input[0]->redirect = 0; -+ port->output->redirect = 0; -+} -+ -+static int dma_alloc(struct pci_dev *pdev, struct ddb_dma *dma) - { - int i; - -- for (i = 0; i < num; i++) { -- vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]); -- if (!vbuf[i]) -+ if (!dma) -+ return 0; -+ for (i = 0; i < dma->num; i++) { -+ dma->vbuf[i] = pci_alloc_consistent(pdev, dma->size, &dma->pbuf[i]); -+ if (!dma->vbuf[i]) - return -ENOMEM; - } - return 0; -@@ -293,34 +392,23 @@ - port = &dev->port[i]; - switch (port->class) { - case DDB_PORT_TUNER: -- if (io_alloc(dev->pdev, port->input[0]->vbuf, -- port->input[0]->pbuf, -- port->input[0]->dma_buf_size, -- port->input[0]->dma_buf_num) < 0) -+ if (dma_alloc(dev->pdev, port->input[0]->dma) < 0) - return -1; -- if (io_alloc(dev->pdev, port->input[1]->vbuf, -- port->input[1]->pbuf, -- port->input[1]->dma_buf_size, -- port->input[1]->dma_buf_num) < 0) -+ if (dma_alloc(dev->pdev, port->input[1]->dma) < 0) - return -1; - break; - case DDB_PORT_CI: -- if (io_alloc(dev->pdev, port->input[0]->vbuf, -- port->input[0]->pbuf, -- port->input[0]->dma_buf_size, -- port->input[0]->dma_buf_num) < 0) -+ case DDB_PORT_LOOP: -+ if (dma_alloc(dev->pdev, port->input[0]->dma) < 0) - return -1; -- if (io_alloc(dev->pdev, port->output->vbuf, -- port->output->pbuf, -- port->output->dma_buf_size, -- port->output->dma_buf_num) < 0) -+ if (dma_alloc(dev->pdev, port->output->dma) < 0) - return -1; - break; - default: - break; - } - } -- ddb_address_table(dev); -+ ddb_set_dma_tables(dev); - return 0; - } - -@@ -331,18 +419,11 @@ - - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; -- io_free(dev->pdev, port->input[0]->vbuf, -- port->input[0]->pbuf, -- port->input[0]->dma_buf_size, -- port->input[0]->dma_buf_num); -- io_free(dev->pdev, port->input[1]->vbuf, -- port->input[1]->pbuf, -- port->input[1]->dma_buf_size, -- port->input[1]->dma_buf_num); -- io_free(dev->pdev, port->output->vbuf, -- port->output->pbuf, -- port->output->dma_buf_size, -- port->output->dma_buf_num); -+ -+ ddb_unredirect(port); -+ dma_free(dev->pdev, port->input[0]->dma); -+ dma_free(dev->pdev, port->input[1]->dma); -+ dma_free(dev->pdev, port->output->dma); - } - } - -@@ -350,90 +431,116 @@ - { - struct ddb *dev = input->port->dev; - -- spin_lock_irq(&input->lock); -- input->cbuf = 0; -- input->coff = 0; -+ spin_lock_irq(&input->dma->lock); -+ input->dma->cbuf = 0; -+ input->dma->coff = 0; - - /* reset */ -- ddbwritel(0, TS_INPUT_CONTROL(input->nr)); -- ddbwritel(2, TS_INPUT_CONTROL(input->nr)); -- ddbwritel(0, TS_INPUT_CONTROL(input->nr)); -- -- ddbwritel((1 << 16) | -- (input->dma_buf_num << 11) | -- (input->dma_buf_size >> 7), -- DMA_BUFFER_SIZE(input->nr)); -- ddbwritel(0, DMA_BUFFER_ACK(input->nr)); -- -- ddbwritel(1, DMA_BASE_WRITE); -- ddbwritel(3, DMA_BUFFER_CONTROL(input->nr)); -- ddbwritel(9, TS_INPUT_CONTROL(input->nr)); -- input->running = 1; -- spin_unlock_irq(&input->lock); -+ ddbwritel(dev, 0, TS_INPUT_CONTROL(input->nr)); -+ ddbwritel(dev, 2, TS_INPUT_CONTROL(input->nr)); -+ ddbwritel(dev, 0, TS_INPUT_CONTROL(input->nr)); -+ -+ ddbwritel(dev, input->dma->bufreg, DMA_BUFFER_SIZE(input->dma->nr)); -+ ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma->nr)); -+ -+ ddbwritel(dev, 1, DMA_BASE_WRITE); -+ ddbwritel(dev, 3, DMA_BUFFER_CONTROL(input->dma->nr)); -+ ddbwritel(dev, 9, TS_INPUT_CONTROL(input->nr)); -+ input->dma->running = 1; -+ spin_unlock_irq(&input->dma->lock); -+ /* printk(KERN_INFO "input_start %d\n", input->nr); */ - } - - static void ddb_input_stop(struct ddb_input *input) - { - struct ddb *dev = input->port->dev; - -- spin_lock_irq(&input->lock); -- ddbwritel(0, TS_INPUT_CONTROL(input->nr)); -- ddbwritel(0, DMA_BUFFER_CONTROL(input->nr)); -- input->running = 0; -- spin_unlock_irq(&input->lock); -+ spin_lock_irq(&input->dma->lock); -+ ddbwritel(dev, 0, TS_INPUT_CONTROL(input->nr)); -+ ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma->nr)); -+ input->dma->running = 0; -+ spin_unlock_irq(&input->dma->lock); - } - - static void ddb_output_start(struct ddb_output *output) - { - struct ddb *dev = output->port->dev; - -- spin_lock_irq(&output->lock); -- output->cbuf = 0; -- output->coff = 0; -- ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); -- ddbwritel(2, TS_OUTPUT_CONTROL(output->nr)); -- ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); -- ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr)); -- ddbwritel((1 << 16) | -- (output->dma_buf_num << 11) | -- (output->dma_buf_size >> 7), -- DMA_BUFFER_SIZE(output->nr + 8)); -- ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8)); -- -- ddbwritel(1, DMA_BASE_READ); -- ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8)); -- /* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */ -- ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr)); -- output->running = 1; -- spin_unlock_irq(&output->lock); -+ spin_lock_irq(&output->dma->lock); -+ output->dma->cbuf = 0; -+ output->dma->coff = 0; -+ ddbwritel(dev, 0, TS_OUTPUT_CONTROL(output->nr)); -+ ddbwritel(dev, 2, TS_OUTPUT_CONTROL(output->nr)); -+ ddbwritel(dev, 0, TS_OUTPUT_CONTROL(output->nr)); -+ ddbwritel(dev, 0x3c, TS_OUTPUT_CONTROL(output->nr)); -+ ddbwritel(dev, output->dma->bufreg, DMA_BUFFER_SIZE(output->dma->nr)); -+ ddbwritel(dev, 0, DMA_BUFFER_ACK(output->dma->nr)); -+ -+ ddbwritel(dev, 1, DMA_BASE_READ); -+ ddbwritel(dev, 3, DMA_BUFFER_CONTROL(output->dma->nr)); -+ if (output->port->input[0]->port->class == DDB_PORT_LOOP) -+ ddbwritel(dev, 0x05, TS_OUTPUT_CONTROL(output->nr)); -+ else -+ ddbwritel(dev, 0x1d, TS_OUTPUT_CONTROL(output->nr)); -+ output->dma->running = 1; -+ spin_unlock_irq(&output->dma->lock); -+ /* printk(KERN_INFO "output_start %d\n", output->nr); */ -+} -+ -+#if 0 -+static void ddb_input_start_all(struct ddb_input *input) -+{ -+ struct ddb_input *next; -+ -+ ddb_input_start(input); -+ while ((next = input->redirect) && -+ next != input) { -+ ddb_input_start(next); -+ ddb_output_start(next->port->output); -+ } - } -+#endif - - static void ddb_output_stop(struct ddb_output *output) - { - struct ddb *dev = output->port->dev; - -- spin_lock_irq(&output->lock); -- ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); -- ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8)); -- output->running = 0; -- spin_unlock_irq(&output->lock); -+ spin_lock_irq(&output->dma->lock); -+ ddbwritel(dev, 0, TS_OUTPUT_CONTROL(output->nr)); -+ ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma->nr)); -+ output->dma->running = 0; -+ spin_unlock_irq(&output->dma->lock); -+} -+ -+#if 0 -+static void ddb_input_stop_all(struct ddb_input *input) -+{ -+ struct ddb_input *next; -+ -+ ddb_input_stop(input); -+ while ((next = input->redirect) && -+ next != input) { -+ ddb_input_stop(next); -+ ddb_output_stop(next->port->output); -+ } - } -+#endif - - static u32 ddb_output_free(struct ddb_output *output) - { -- u32 idx, off, stat = output->stat; -+ u32 idx, off, stat = output->dma->stat; - s32 diff; - - idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; - -- if (output->cbuf != idx) { -- if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && -- (output->dma_buf_size - output->coff <= 188)) -+ if (output->dma->cbuf != idx) { -+ if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && -+ (output->dma->size - output->dma->coff <= 188)) - return 0; - return 188; - } -- diff = off - output->coff; -+ diff = off - output->dma->coff; - if (diff <= 0 || diff > 188) - return 188; - return 0; -@@ -443,24 +550,24 @@ - const u8 *buf, size_t count) - { - struct ddb *dev = output->port->dev; -- u32 idx, off, stat = output->stat; -+ u32 idx, off, stat = output->dma->stat; - u32 left = count, len; - - idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; - - while (left) { -- len = output->dma_buf_size - output->coff; -- if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && -+ len = output->dma->size - output->dma->coff; -+ if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && - (off == 0)) { - if (len <= 188) - break; - len -= 188; - } -- if (output->cbuf == idx) { -- if (off > output->coff) { -+ if (output->dma->cbuf == idx) { -+ if (off > output->dma->coff) { - #if 1 -- len = off - output->coff; -+ len = off - output->dma->coff; - len -= (len % 188); - if (len <= 188) - -@@ -471,68 +578,146 @@ - } - if (len > left) - len = left; -- if (copy_from_user(output->vbuf[output->cbuf] + output->coff, -+ if (copy_from_user(output->dma->vbuf[output->dma->cbuf] + -+ output->dma->coff, - buf, len)) - return -EIO; -+ /* printk("cfu %d %d %d\n", len, output->cbuf, output->coff); */ - left -= len; - buf += len; -- output->coff += len; -- if (output->coff == output->dma_buf_size) { -- output->coff = 0; -- output->cbuf = ((output->cbuf + 1) % output->dma_buf_num); -+ output->dma->coff += len; -+ if (output->dma->coff == output->dma->size) { -+ output->dma->coff = 0; -+ output->dma->cbuf = ((output->dma->cbuf + 1) % -+ output->dma->num); - } -- ddbwritel((output->cbuf << 11) | (output->coff >> 7), -- DMA_BUFFER_ACK(output->nr + 8)); -+ ddbwritel(dev, (output->dma->cbuf << 11) | (output->dma->coff >> 7), -+ DMA_BUFFER_ACK(output->dma->nr)); - } - return count - left; - } - -+#if 0 -+static u32 ddb_input_free_bytes(struct ddb_input *input) -+{ -+ struct ddb *dev = input->port->dev; -+ u32 idx, off, stat = input->dma->stat; -+ u32 ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(input->dma->nr)); -+ -+ idx = (stat >> 11) & 0x1f; -+ off = (stat & 0x7ff) << 7; -+ -+ if (ctrl & 4) -+ return 0; -+ if (input->dma->cbuf != idx) -+ return 1; -+ return 0; -+} -+ -+static s32 ddb_output_used_bufs(struct ddb_output *output) -+{ -+ u32 idx, off, stat, ctrl; -+ s32 diff; -+ -+ spin_lock_irq(&output->dma->lock); -+ stat = output->dma->stat; -+ ctrl = output->dma->ctrl; -+ spin_unlock_irq(&output->dma->lock); -+ -+ idx = (stat >> 11) & 0x1f; -+ off = (stat & 0x7ff) << 7; -+ -+ if (ctrl & 4) -+ return 0; -+ diff = output->dma->cbuf - idx; -+ if (diff == 0 && off < output->dma->coff) -+ return 0; -+ if (diff <= 0) -+ diff += output->dma->num; -+ return diff; -+} -+ -+static s32 ddb_input_free_bufs(struct ddb_input *input) -+{ -+ u32 idx, off, stat, ctrl; -+ s32 free; -+ -+ spin_lock_irq(&input->dma->lock); -+ ctrl = input->dma->ctrl; -+ stat = input->dma->stat; -+ spin_unlock_irq(&input->dma->lock); -+ if (ctrl & 4) -+ return 0; -+ idx = (stat >> 11) & 0x1f; -+ off = (stat & 0x7ff) << 7; -+ free = input->dma->cbuf - idx; -+ if (free == 0 && off < input->dma->coff) -+ return 0; -+ if (free <= 0) -+ free += input->dma->num; -+ return free - 1; -+} -+ -+static u32 ddb_output_ok(struct ddb_output *output) -+{ -+ struct ddb_input *input = output->port->input[0]; -+ s32 diff; -+ -+ diff = ddb_input_free_bufs(input) - ddb_output_used_bufs(output); -+ if (diff > 0) -+ return 1; -+ return 0; -+} -+#endif -+ - static u32 ddb_input_avail(struct ddb_input *input) - { - struct ddb *dev = input->port->dev; -- u32 idx, off, stat = input->stat; -- u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr)); -+ u32 idx, off, stat = input->dma->stat; -+ u32 ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(input->dma->nr)); - - idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; - - if (ctrl & 4) { - printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl); -- ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr)); -+ ddbwritel(dev, stat, DMA_BUFFER_ACK(input->dma->nr)); - return 0; - } -- if (input->cbuf != idx) -+ if (input->dma->cbuf != idx || off < input->dma->coff) - return 188; - return 0; - } - --static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) -+static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) - { - struct ddb *dev = input->port->dev; - u32 left = count; -- u32 idx, free, stat = input->stat; -+ u32 idx, off, free, stat = input->dma->stat; - int ret; - - idx = (stat >> 11) & 0x1f; -+ off = (stat & 0x7ff) << 7; - - while (left) { -- if (input->cbuf == idx) -+ if (input->dma->cbuf == idx) - return count - left; -- free = input->dma_buf_size - input->coff; -+ free = input->dma->size - input->dma->coff; - if (free > left) - free = left; -- ret = copy_to_user(buf, input->vbuf[input->cbuf] + -- input->coff, free); -+ ret = copy_to_user(buf, input->dma->vbuf[input->dma->cbuf] + -+ input->dma->coff, free); - if (ret) - return -EFAULT; -- input->coff += free; -- if (input->coff == input->dma_buf_size) { -- input->coff = 0; -- input->cbuf = (input->cbuf+1) % input->dma_buf_num; -+ input->dma->coff += free; -+ if (input->dma->coff == input->dma->size) { -+ input->dma->coff = 0; -+ input->dma->cbuf = (input->dma->cbuf+1) % -+ input->dma->num; - } - left -= free; -- ddbwritel((input->cbuf << 11) | (input->coff >> 7), -- DMA_BUFFER_ACK(input->nr)); -+ ddbwritel(dev, (input->dma->cbuf << 11) | (input->dma->coff >> 7), -+ DMA_BUFFER_ACK(input->dma->nr)); - } - return count; - } -@@ -554,7 +739,7 @@ - } - #endif - --static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) -+static int locked_gate_ctrl(struct dvb_frontend *fe, int enable) - { - struct ddb_input *input = fe->sec_priv; - struct ddb_port *port = input->port; -@@ -562,9 +747,9 @@ - - if (enable) { - mutex_lock(&port->i2c_gate_lock); -- status = input->gate_ctrl(fe, 1); -+ status = input->dvb.gate_ctrl(fe, 1); - } else { -- status = input->gate_ctrl(fe, 0); -+ status = input->dvb.gate_ctrl(fe, 0); - mutex_unlock(&port->i2c_gate_lock); - } - return status; -@@ -577,18 +762,88 @@ - struct drxk_config config; - - memset(&config, 0, sizeof(config)); -- config.microcode_name = "drxk_a3.mc"; -- config.qam_demod_parameter_count = 4; - config.adr = 0x29 + (input->nr & 1); -+ config.microcode_name = "drxk_a3.mc"; - -- fe = input->fe = dvb_attach(drxk_attach, &config, i2c); -- if (!input->fe) { -+#ifdef USE_API3 -+ fe = input->dvb.fe = dvb_attach(drxk_attach, &config, i2c, &input->dvb.fe2); -+#else -+ fe = input->dvb.fe = dvb_attach(drxk_attach, &config, i2c); -+#endif -+ if (!input->dvb.fe) { - printk(KERN_ERR "No DRXK found!\n"); - return -ENODEV; - } - fe->sec_priv = input; -- input->gate_ctrl = fe->ops.i2c_gate_ctrl; -- fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; -+ input->dvb.gate_ctrl = fe->ops.i2c_gate_ctrl; -+ fe->ops.i2c_gate_ctrl = locked_gate_ctrl; -+ return 0; -+} -+ -+#if 0 -+struct stv0367_config stv0367_0 = { -+ .demod_address = 0x1f, -+ .xtal = 27000000, -+ .if_khz = 5000, -+ .if_iq_mode = FE_TER_NORMAL_IF_TUNER, -+ .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, -+ .clk_pol = STV0367_RISINGEDGE_CLOCK, -+}; -+ -+struct stv0367_config stv0367_1 = { -+ .demod_address = 0x1e, -+ .xtal = 27000000, -+ .if_khz = 5000, -+ .if_iq_mode = FE_TER_NORMAL_IF_TUNER, -+ .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, -+ .clk_pol = STV0367_RISINGEDGE_CLOCK, -+}; -+ -+ -+static int demod_attach_stv0367(struct ddb_input *input) -+{ -+ struct i2c_adapter *i2c = &input->port->i2c->adap; -+ struct dvb_frontend *fe; -+ -+ fe = input->dvb.fe = dvb_attach(stv0367ter_attach, -+ (input->nr & 1) ? &stv0367_1 : &stv0367_0, -+ i2c); -+ if (!input->dvb.fe) { -+ printk(KERN_ERR "No stv0367 found!\n"); -+ return -ENODEV; -+ } -+ fe->sec_priv = input; -+ input->dvb.gate_ctrl = fe->ops.i2c_gate_ctrl; -+ fe->ops.i2c_gate_ctrl = locked_gate_ctrl; -+ return 0; -+} -+#endif -+ -+struct stv0367_cfg stv0367dd_0 = { -+ .adr = 0x1f, -+ .xtal = 27000000, -+}; -+ -+struct stv0367_cfg stv0367dd_1 = { -+ .adr = 0x1e, -+ .xtal = 27000000, -+}; -+ -+static int demod_attach_stv0367dd(struct ddb_input *input) -+{ -+ struct i2c_adapter *i2c = &input->port->i2c->adap; -+ struct dvb_frontend *fe; -+ -+ fe = input->dvb.fe = dvb_attach(stv0367_attach, i2c, -+ (input->nr & 1) ? &stv0367dd_1 : &stv0367dd_0, -+ &input->dvb.fe2); -+ if (!input->dvb.fe) { -+ printk(KERN_ERR "No stv0367 found!\n"); -+ return -ENODEV; -+ } -+ fe->sec_priv = input; -+ input->dvb.gate_ctrl = fe->ops.i2c_gate_ctrl; -+ fe->ops.i2c_gate_ctrl = locked_gate_ctrl; - return 0; - } - -@@ -597,18 +852,57 @@ - struct i2c_adapter *i2c = &input->port->i2c->adap; - struct dvb_frontend *fe; - -- if (input->fe->ops.i2c_gate_ctrl) -- input->fe->ops.i2c_gate_ctrl(input->fe, 1); -- fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60); -+ if (input->dvb.fe->ops.i2c_gate_ctrl) -+ input->dvb.fe->ops.i2c_gate_ctrl(input->dvb.fe, 1); -+ fe = dvb_attach(tda18271c2dd_attach, input->dvb.fe, i2c, 0x60); -+ if (input->dvb.fe->ops.i2c_gate_ctrl) -+ input->dvb.fe->ops.i2c_gate_ctrl(input->dvb.fe, 0); - if (!fe) { - printk(KERN_ERR "No TDA18271 found!\n"); - return -ENODEV; - } -- if (input->fe->ops.i2c_gate_ctrl) -- input->fe->ops.i2c_gate_ctrl(input->fe, 0); - return 0; - } - -+static int tuner_attach_tda18212dd(struct ddb_input *input) -+{ -+ struct i2c_adapter *i2c = &input->port->i2c->adap; -+ struct dvb_frontend *fe; -+ -+ fe = dvb_attach(tda18212dd_attach, input->dvb.fe, i2c, -+ (input->nr & 1) ? 0x63 : 0x60); -+ if (!fe) { -+ printk(KERN_ERR "No TDA18212 found!\n"); -+ return -ENODEV; -+ } -+ return 0; -+} -+ -+#if 0 -+struct tda18212_config tda18212_0 = { -+ .i2c_address = 0x60, -+}; -+ -+struct tda18212_config tda18212_1 = { -+ .i2c_address = 0x63, -+}; -+ -+static int tuner_attach_tda18212(struct ddb_input *input) -+{ -+ struct i2c_adapter *i2c = &input->port->i2c->adap; -+ struct dvb_frontend *fe; -+ struct tda18212_config *cfg; -+ -+ cfg = (input->nr & 1) ? &tda18212_1 : &tda18212_0; -+ fe = dvb_attach(tda18212_attach, input->dvb.fe, i2c, cfg); -+ if (!fe) { -+ printk(KERN_ERR "No TDA18212 found!\n"); -+ return -ENODEV; -+ } -+ return 0; -+} -+#endif -+ - /******************************************************************************/ - /******************************************************************************/ - /******************************************************************************/ -@@ -668,14 +962,14 @@ - struct i2c_adapter *i2c = &input->port->i2c->adap; - struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; - -- input->fe = dvb_attach(stv090x_attach, feconf, i2c, -+ input->dvb.fe = dvb_attach(stv090x_attach, feconf, i2c, - (input->nr & 1) ? STV090x_DEMODULATOR_1 - : STV090x_DEMODULATOR_0); -- if (!input->fe) { -+ if (!input->dvb.fe) { - printk(KERN_ERR "No STV0900 found!\n"); - return -ENODEV; - } -- if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0, -+ if (!dvb_attach(lnbh24_attach, input->dvb.fe, i2c, 0, - 0, (input->nr & 1) ? - (0x09 - type) : (0x0b - type))) { - printk(KERN_ERR "No LNBH24 found!\n"); -@@ -692,7 +986,7 @@ - &stv6110b : &stv6110a; - struct stv6110x_devctl *ctl; - -- ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c); -+ ctl = dvb_attach(stv6110x_attach, input->dvb.fe, tunerconf, i2c); - if (!ctl) { - printk(KERN_ERR "No STV6110X found!\n"); - return -ENODEV; -@@ -760,10 +1054,10 @@ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct ddb_input *input = dvbdmx->priv; - -- if (!input->users) -+ if (!input->dvb.users) - ddb_input_start(input); - -- return ++input->users; -+ return ++input->dvb.users; - } - - static int stop_feed(struct dvb_demux_feed *dvbdmxfeed) -@@ -771,8 +1065,8 @@ - struct dvb_demux *dvbdmx = dvbdmxfeed->demux; - struct ddb_input *input = dvbdmx->priv; - -- if (--input->users) -- return input->users; -+ if (--input->dvb.users) -+ return input->dvb.users; - - ddb_input_stop(input); - return 0; -@@ -781,116 +1075,200 @@ - - static void dvb_input_detach(struct ddb_input *input) - { -- struct dvb_adapter *adap = &input->adap; -- struct dvb_demux *dvbdemux = &input->demux; -+ struct dvb_demux *dvbdemux = &input->dvb.demux; - -- switch (input->attached) { -+ switch (input->dvb.attached) { -+ case 6: -+ if (input->dvb.fe2) -+ dvb_unregister_frontend(input->dvb.fe2); -+ if (input->dvb.fe) -+ dvb_unregister_frontend(input->dvb.fe); - case 5: -- if (input->fe2) -- dvb_unregister_frontend(input->fe2); -- if (input->fe) { -- dvb_unregister_frontend(input->fe); -- dvb_frontend_detach(input->fe); -- input->fe = NULL; -- } -+ dvb_frontend_detach(input->dvb.fe); -+ input->dvb.fe = NULL; - case 4: -- dvb_net_release(&input->dvbnet); -- -+ dvb_net_release(&input->dvb.dvbnet); - case 3: - dvbdemux->dmx.close(&dvbdemux->dmx); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, -- &input->hw_frontend); -+ &input->dvb.hw_frontend); - dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, -- &input->mem_frontend); -- dvb_dmxdev_release(&input->dmxdev); -- -+ &input->dvb.mem_frontend); -+ dvb_dmxdev_release(&input->dvb.dmxdev); - case 2: -- dvb_dmx_release(&input->demux); -- -+ dvb_dmx_release(&input->dvb.demux); - case 1: -- dvb_unregister_adapter(adap); -+ break; -+ } -+ input->dvb.attached = 0; -+} -+ -+static int dvb_register_adapters(struct ddb *dev) -+{ -+ int i, ret = 0; -+ struct ddb_port *port; -+ struct dvb_adapter *adap; -+ -+ if (adapter_alloc == 3) { -+ port = &dev->port[0]; -+ adap = port->input[0]->dvb.adap; -+ ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, -+ &port->dev->pdev->dev, -+ adapter_nr); -+ if (ret < 0) -+ return ret; -+ port->input[0]->dvb.adap_registered = 1; -+ for (i = 0; i < dev->info->port_num; i++) { -+ port = &dev->port[i]; -+ port->input[0]->dvb.adap = adap; -+ port->input[1]->dvb.adap = adap; -+ } -+ return 0; -+ } -+ -+ for (i = 0; i < dev->info->port_num; i++) { -+ port = &dev->port[i]; -+ switch (port->class) { -+ case DDB_PORT_TUNER: -+ adap = port->input[0]->dvb.adap; -+ ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, -+ &port->dev->pdev->dev, -+ adapter_nr); -+ if (ret < 0) -+ return ret; -+ port->input[0]->dvb.adap_registered = 1; -+ -+ if (adapter_alloc > 0) { -+ port->input[1]->dvb.adap = port->input[0]->dvb.adap; -+ break; -+ } -+ adap = port->input[1]->dvb.adap; -+ ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, -+ &port->dev->pdev->dev, -+ adapter_nr); -+ if (ret < 0) -+ return ret; -+ port->input[1]->dvb.adap_registered = 1; -+ break; -+ -+ case DDB_PORT_CI: -+ case DDB_PORT_LOOP: -+ adap = port->input[0]->dvb.adap; -+ ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, -+ &port->dev->pdev->dev, -+ adapter_nr); -+ if (ret < 0) -+ return ret; -+ port->input[0]->dvb.adap_registered = 1; -+ break; -+ default: -+ if (adapter_alloc < 2) -+ break; -+ adap = port->input[0]->dvb.adap; -+ ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, -+ &port->dev->pdev->dev, -+ adapter_nr); -+ if (ret < 0) -+ return ret; -+ port->input[0]->dvb.adap_registered = 1; -+ break; -+ } -+ } -+ return ret; -+} -+ -+static void dvb_unregister_adapters(struct ddb *dev) -+{ -+ int i; -+ struct ddb_port *port; -+ struct ddb_input *input; -+ -+ for (i = 0; i < dev->info->port_num; i++) { -+ port = &dev->port[i]; -+ -+ input = port->input[0]; -+ if (input->dvb.adap_registered) -+ dvb_unregister_adapter(input->dvb.adap); -+ input->dvb.adap_registered = 0; -+ -+ input = port->input[1]; -+ if (input->dvb.adap_registered) -+ dvb_unregister_adapter(input->dvb.adap); -+ input->dvb.adap_registered = 0; - } -- input->attached = 0; - } - -+ - static int dvb_input_attach(struct ddb_input *input) - { -- int ret; -+ int ret = 0; - struct ddb_port *port = input->port; -- struct dvb_adapter *adap = &input->adap; -- struct dvb_demux *dvbdemux = &input->demux; -+ struct dvb_adapter *adap = input->dvb.adap; -+ struct dvb_demux *dvbdemux = &input->dvb.demux; - -- ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, -- &input->port->dev->pdev->dev, -- adapter_nr); -- if (ret < 0) { -- printk(KERN_ERR "ddbridge: Could not register adapter." -- "Check if you enabled enough adapters in dvb-core!\n"); -- return ret; -- } -- input->attached = 1; -+ input->dvb.attached = 1; - - ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", - start_feed, - stop_feed, input); - if (ret < 0) - return ret; -- input->attached = 2; -+ input->dvb.attached = 2; - -- ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux, -- &input->hw_frontend, -- &input->mem_frontend, adap); -+ ret = my_dvb_dmxdev_ts_card_init(&input->dvb.dmxdev, -+ &input->dvb.demux, -+ &input->dvb.hw_frontend, -+ &input->dvb.mem_frontend, adap); - if (ret < 0) - return ret; -- input->attached = 3; -+ input->dvb.attached = 3; - -- ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux); -+ ret = dvb_net_init(adap, &input->dvb.dvbnet, input->dvb.dmxdev.demux); - if (ret < 0) - return ret; -- input->attached = 4; -+ input->dvb.attached = 4; - -- input->fe = 0; -+ input->dvb.fe = 0; - switch (port->type) { - case DDB_TUNER_DVBS_ST: - if (demod_attach_stv0900(input, 0) < 0) - return -ENODEV; - if (tuner_attach_stv6110(input, 0) < 0) - return -ENODEV; -- if (input->fe) { -- if (dvb_register_frontend(adap, input->fe) < 0) -- return -ENODEV; -- } - break; - case DDB_TUNER_DVBS_ST_AA: - if (demod_attach_stv0900(input, 1) < 0) - return -ENODEV; - if (tuner_attach_stv6110(input, 1) < 0) - return -ENODEV; -- if (input->fe) { -- if (dvb_register_frontend(adap, input->fe) < 0) -- return -ENODEV; -- } - break; - case DDB_TUNER_DVBCT_TR: - if (demod_attach_drxk(input) < 0) - return -ENODEV; - if (tuner_attach_tda18271(input) < 0) - return -ENODEV; -- if (input->fe) { -- if (dvb_register_frontend(adap, input->fe) < 0) -- return -ENODEV; -- } -- if (input->fe2) { -- if (dvb_register_frontend(adap, input->fe2) < 0) -- return -ENODEV; -- input->fe2->tuner_priv = input->fe->tuner_priv; -- memcpy(&input->fe2->ops.tuner_ops, -- &input->fe->ops.tuner_ops, -- sizeof(struct dvb_tuner_ops)); -- } - break; -+ case DDB_TUNER_DVBCT_ST: -+ if (demod_attach_stv0367dd(input) < 0) -+ return -ENODEV; -+ if (tuner_attach_tda18212dd(input) < 0) -+ return -ENODEV; -+ break; -+ } -+ input->dvb.attached = 5; -+ if (input->dvb.fe) { -+ if (dvb_register_frontend(adap, input->dvb.fe) < 0) -+ return -ENODEV; -+ } -+ if (input->dvb.fe2) { -+ if (dvb_register_frontend(adap, input->dvb.fe2) < 0) -+ return -ENODEV; -+ input->dvb.fe2->tuner_priv = input->dvb.fe->tuner_priv; -+ memcpy(&input->dvb.fe2->ops.tuner_ops, -+ &input->dvb.fe->ops.tuner_ops, -+ sizeof(struct dvb_tuner_ops)); - } -- input->attached = 5; -+ input->dvb.attached = 6; - return 0; - } - -@@ -910,7 +1288,8 @@ - if (file->f_flags & O_NONBLOCK) - break; - if (wait_event_interruptible( -- output->wq, ddb_output_free(output) >= 188) < 0) -+ output->dma->wq, -+ ddb_output_free(output) >= 188) < 0) - break; - } - stat = ddb_output_write(output, buf, left); -@@ -937,7 +1316,7 @@ - if (file->f_flags & O_NONBLOCK) - break; - if (wait_event_interruptible( -- input->wq, ddb_input_avail(input) >= 188) < 0) -+ input->dma->wq, ddb_input_avail(input) >= 188) < 0) - break; - } - read = ddb_input_read(input, buf, left); -@@ -970,21 +1349,53 @@ - return mask; - } - --static const struct file_operations ci_fops = { -- .owner = THIS_MODULE, -- .read = ts_read, -- .write = ts_write, -- .open = dvb_generic_open, -- .release = dvb_generic_release, -- .poll = ts_poll, -- .mmap = 0, --}; -- --static struct dvb_device dvbdev_ci = { -+#if 0 -+static int ts_release(struct inode *inode, struct file *file) -+{ -+ struct dvb_device *dvbdev = file->private_data; -+ struct ddb_output *output = dvbdev->priv; -+ struct ddb_input *input = output->port->input[0]; -+ -+ -+ return dvb_generic_release(inode, file); -+} -+ -+static unsigned int ts_open(struct inode *inode, struct file *file) -+{ -+ int err; -+ struct dvb_device *dvbdev = file->private_data; -+ struct ddb_output *output = dvbdev->priv; -+ struct ddb_input *input = output->port->input[0]; -+ -+ err = dvb_generic_open(inode, file); -+ if (err < 0) -+ return err; -+ -+#if 0 -+ if ((file->f_flags & O_ACCMODE) == O_RDONLY) -+ ddb_input_start(input); -+ else -+ ddb_output_start(output); -+#endif -+ return err; -+} -+#endif -+ -+static const struct file_operations ci_fops = { -+ .owner = THIS_MODULE, -+ .read = ts_read, -+ .write = ts_write, -+ .open = dvb_generic_open, -+ .release = dvb_generic_release, -+ .poll = ts_poll, -+ .mmap = 0, -+}; -+ -+static struct dvb_device dvbdev_ci = { - .priv = 0, -- .readers = -1, -- .writers = -1, -- .users = -1, -+ .readers = 1, -+ .writers = 1, -+ .users = 2, - .fops = &ci_fops, - }; - -@@ -992,53 +1403,297 @@ - /****************************************************************************/ - /****************************************************************************/ - -+static int set_redirect(u32 i, u32 p) -+{ -+ struct ddb *idev = ddbs[(i >> 4) & 0x1f]; -+ struct ddb_input *input; -+ struct ddb *pdev = ddbs[(p >> 4) & 0x1f]; -+ struct ddb_port *port; -+ -+ if (!idev || !pdev) -+ return -EINVAL; -+ -+ port = &pdev->port[p & 3]; -+ if (port->class != DDB_PORT_CI && port->class != DDB_PORT_LOOP) -+ return -EINVAL; -+ -+ ddb_unredirect(port); -+ if (i == 8) -+ return 0; -+ input = &idev->input[i & 7]; -+ if (input->port->class != DDB_PORT_TUNER) -+ port->input[0]->redirect = input->redirect; -+ else -+ port->input[0]->redirect = input; -+ input->redirect = port->input[0]; -+ port->output->redirect = input; -+ -+ ddb_redirect_dma(input->port->dev, input->dma, port->output->dma); -+ return 0; -+} -+ -+static void input_write_output(struct ddb_input *input, -+ struct ddb_output *output) -+{ -+ ddbwritel(output->port->dev, -+ input->dma->stat, DMA_BUFFER_ACK(output->dma->nr)); -+} -+ -+static void output_ack_input(struct ddb_output *output, -+ struct ddb_input *input) -+{ -+ ddbwritel(input->port->dev, -+ output->dma->stat, DMA_BUFFER_ACK(input->dma->nr)); -+} -+ -+static void input_write_dvb(struct ddb_input *input, struct ddb_dvb *dvb) -+{ -+ struct ddb_dma *dma = input->dma; -+ struct ddb *dev = input->port->dev; -+ -+ if (4 & ddbreadl(dev, DMA_BUFFER_CONTROL(dma->nr))) -+ printk(KERN_ERR "Overflow dma %d\n", dma->nr); -+ while (dma->cbuf != ((dma->stat >> 11) & 0x1f) -+ || (4 & ddbreadl(dev, DMA_BUFFER_CONTROL(dma->nr)))) { -+ dvb_dmx_swfilter_packets(&dvb->demux, -+ dma->vbuf[dma->cbuf], -+ dma->size / 188); -+ dma->cbuf = (dma->cbuf + 1) % dma->num; -+ ddbwritel(dev, (dma->cbuf << 11), DMA_BUFFER_ACK(dma->nr)); -+ dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma->nr)); -+ } -+} -+ - static void input_tasklet(unsigned long data) - { - struct ddb_input *input = (struct ddb_input *) data; -+ struct ddb_dma *dma = input->dma; - struct ddb *dev = input->port->dev; - -- spin_lock(&input->lock); -- if (!input->running) { -- spin_unlock(&input->lock); -+ spin_lock(&dma->lock); -+ if (!dma->running) { -+ spin_unlock(&dma->lock); - return; - } -- input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); -+ dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma->nr)); - - if (input->port->class == DDB_PORT_TUNER) { -- if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr))) -- printk(KERN_ERR "Overflow input %d\n", input->nr); -- while (input->cbuf != ((input->stat >> 11) & 0x1f) -- || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))) { -- dvb_dmx_swfilter_packets(&input->demux, -- input->vbuf[input->cbuf], -- input->dma_buf_size / 188); -- -- input->cbuf = (input->cbuf + 1) % input->dma_buf_num; -- ddbwritel((input->cbuf << 11), -- DMA_BUFFER_ACK(input->nr)); -- input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); -- } -- } -- if (input->port->class == DDB_PORT_CI) -- wake_up(&input->wq); -- spin_unlock(&input->lock); -+ if (input->redirect) -+ input_write_output(input, -+ input->redirect->port->output); -+ else -+ input_write_dvb(input, &input->dvb); -+ } -+ if (input->port->class == DDB_PORT_CI || -+ input->port->class == DDB_PORT_LOOP) { -+ if (input->redirect) { -+ if (input->redirect->port->class == DDB_PORT_TUNER) -+ input_write_dvb(input, &input->redirect->dvb); -+ else -+ input_write_output(input, -+ input->redirect->port->output); -+ } else -+ wake_up(&dma->wq); -+ } -+ spin_unlock(&dma->lock); - } - - static void output_tasklet(unsigned long data) - { - struct ddb_output *output = (struct ddb_output *) data; -+ struct ddb_dma *dma = output->dma; - struct ddb *dev = output->port->dev; - -- spin_lock(&output->lock); -- if (!output->running) { -- spin_unlock(&output->lock); -+ spin_lock(&dma->lock); -+ if (!dma->running) { -+ spin_unlock(&dma->lock); - return; - } -- output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8)); -- wake_up(&output->wq); -- spin_unlock(&output->lock); -+ dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma->nr)); -+ dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma->nr)); -+ if (output->redirect) -+ output_ack_input(output, output->redirect); -+ wake_up(&dma->wq); -+ spin_unlock(&dma->lock); -+} -+ -+#if 0 -+static void io_tasklet(unsigned long data) -+{ -+ struct ddb_dma *dma = (struct ddb_dma *) data; -+ -+ spin_lock(&dma->lock); -+ if (!dma->running) { -+ spin_unlock(&dma->lock); -+ return; -+ } -+ dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma->nr)); -+ dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma->nr)); -+ if (dma->nr & 8) -+ handle_output((struct ddb_output *) dma->io); -+ else -+ handle_input((struct ddb_input *) dma->io); -+ wake_up(&dma->wq); -+ spin_unlock(&dma->lock); -+} -+#endif -+ -+/****************************************************************************/ -+/****************************************************************************/ -+/****************************************************************************/ -+ -+static int wait_ci_ready(struct ddb_ci *ci) -+{ -+ u32 count = 100; -+ -+ do { -+ if (ddbreadl(ci->port->dev, -+ CI_CONTROL(ci->nr)) & CI_READY) -+ break; -+ msleep(1); -+ if ((--count) == 0) -+ return -1; -+ } while (1); -+ return 0; -+} -+ -+static int read_attribute_mem(struct dvb_ca_en50221 *ca, -+ int slot, int address) -+{ -+ struct ddb_ci *ci = ca->data; -+ u32 val, off = (address >> 1) & (CI_BUFFER_SIZE-1); -+ -+ if (address > CI_BUFFER_SIZE) -+ return -1; -+ ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address, -+ CI_DO_READ_ATTRIBUTES(ci->nr)); -+ wait_ci_ready(ci); -+ val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off); -+ /* printk("%04x: %02x\n", address, val); */ -+ return val; -+} -+ -+static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, -+ int address, u8 value) -+{ -+ struct ddb_ci *ci = ca->data; -+ -+ ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address, -+ CI_DO_ATTRIBUTE_RW(ci->nr)); -+ wait_ci_ready(ci); -+ return 0; -+} -+ -+static int read_cam_control(struct dvb_ca_en50221 *ca, -+ int slot, u8 address) -+{ -+ u32 count = 100; -+ struct ddb_ci *ci = ca->data; -+ u32 res; -+ -+ ddbwritel(ci->port->dev, CI_READ_CMD | address, -+ CI_DO_IO_RW(ci->nr)); -+ do { -+ res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr)); -+ if (res & CI_READY) -+ break; -+ msleep(1); -+ if ((--count) == 0) -+ return -1; -+ } while (1); -+ return 0xff & res; -+} -+ -+static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, -+ u8 address, u8 value) -+{ -+ struct ddb_ci *ci = ca->data; -+ -+ ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address, -+ CI_DO_IO_RW(ci->nr)); -+ wait_ci_ready(ci); -+ return 0; - } - -+static int slot_reset(struct dvb_ca_en50221 *ca, int slot) -+{ -+ struct ddb_ci *ci = ca->data; -+ -+ printk(KERN_INFO "slot reset %d\n", ci->nr); -+ ddbwritel(ci->port->dev, CI_POWER_ON, -+ CI_CONTROL(ci->nr)); -+ msleep(300); -+ ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM, -+ CI_CONTROL(ci->nr)); -+ ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM, -+ CI_CONTROL(ci->nr)); -+ udelay(20); -+ ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON, -+ CI_CONTROL(ci->nr)); -+ return 0; -+} -+ -+static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) -+{ -+ struct ddb_ci *ci = ca->data; -+ -+ printk(KERN_INFO "slot shutdown\n"); -+ ddbwritel(ci->port->dev, 0, CI_CONTROL(ci->nr)); -+ return 0; -+} -+ -+static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) -+{ -+ struct ddb_ci *ci = ca->data; -+ u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr)); -+ -+ ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE, -+ CI_CONTROL(ci->nr)); -+ return 0; -+} -+ -+static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) -+{ -+ struct ddb_ci *ci = ca->data; -+ u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr)); -+ int stat = 0; -+ -+ if (val & CI_CAM_DETECT) -+ stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; -+ if (val & CI_CAM_READY) -+ stat |= DVB_CA_EN50221_POLL_CAM_READY; -+ return stat; -+} -+ -+static struct dvb_ca_en50221 en_templ = { -+ .read_attribute_mem = read_attribute_mem, -+ .write_attribute_mem = write_attribute_mem, -+ .read_cam_control = read_cam_control, -+ .write_cam_control = write_cam_control, -+ .slot_reset = slot_reset, -+ .slot_shutdown = slot_shutdown, -+ .slot_ts_enable = slot_ts_enable, -+ .poll_slot_status = poll_slot_status, -+}; -+ -+static void ci_attach(struct ddb_port *port) -+{ -+ struct ddb_ci *ci = 0; -+ -+ ci = kzalloc(sizeof(*ci), GFP_KERNEL); -+ if (!ci) -+ return; -+ memcpy(&ci->en, &en_templ, sizeof(en_templ)); -+ ci->en.data = ci; -+ port->en = &ci->en; -+ ci->port = port; -+ ci->nr = port->nr - 2; -+} -+ -+/****************************************************************************/ -+/****************************************************************************/ -+/****************************************************************************/ -+ - - struct cxd2099_cfg cxd_cfg = { - .bitrate = 62000, -@@ -1049,28 +1704,22 @@ - - static int ddb_ci_attach(struct ddb_port *port) - { -- int ret; -- -- ret = dvb_register_adapter(&port->output->adap, -- "DDBridge", -- THIS_MODULE, -- &port->dev->pdev->dev, -- adapter_nr); -- if (ret < 0) -- return ret; -- port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); -- if (!port->en) { -- dvb_unregister_adapter(&port->output->adap); -- return -ENODEV; -+ if (port->type == DDB_CI_EXTERNAL_SONY) { -+ port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); -+ if (!port->en) -+ return -ENODEV; -+ dvb_ca_en50221_init(port->input[0]->dvb.adap, -+ port->en, 0, 1); - } -- ddb_input_start(port->input[0]); -- ddb_output_start(port->output); -- dvb_ca_en50221_init(&port->output->adap, -- port->en, 0, 1); -- ret = dvb_register_device(&port->output->adap, &port->output->dev, -- &dvbdev_ci, (void *) port->output, -- DVB_DEVICE_SEC); -- return ret; -+#if 1 -+ if (port->type == DDB_CI_INTERNAL) { -+ ci_attach(port); -+ if (!port->en) -+ return -ENODEV; -+ dvb_ca_en50221_init(port->input[0]->dvb.adap, port->en, 0, 1); -+ } -+#endif -+ return 0; - } - - static int ddb_port_attach(struct ddb_port *port) -@@ -1086,6 +1735,15 @@ - break; - case DDB_PORT_CI: - ret = ddb_ci_attach(port); -+ if (ret < 0) -+ break; -+ case DDB_PORT_LOOP: -+ ddb_input_start(port->input[0]); -+ ddb_output_start(port->output); -+ ret = dvb_register_device(port->input[0]->dvb.adap, -+ &port->input[0]->dvb.dev, -+ &dvbdev_ci, (void *) port->output, -+ DVB_DEVICE_SEC); - break; - default: - break; -@@ -1100,6 +1758,10 @@ - int i, ret = 0; - struct ddb_port *port; - -+ ret = dvb_register_adapters(dev); -+ if (ret < 0) -+ return ret; -+ - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; - ret = ddb_port_attach(port); -@@ -1122,25 +1784,26 @@ - dvb_input_detach(port->input[1]); - break; - case DDB_PORT_CI: -- if (port->output->dev) -- dvb_unregister_device(port->output->dev); -+ case DDB_PORT_LOOP: -+ if (port->input[0]->dvb.dev) -+ dvb_unregister_device(port->input[0]->dvb.dev); -+ ddb_input_stop(port->input[0]); -+ ddb_output_stop(port->output); - if (port->en) { -- ddb_input_stop(port->input[0]); -- ddb_output_stop(port->output); - dvb_ca_en50221_release(port->en); - kfree(port->en); - port->en = 0; -- dvb_unregister_adapter(&port->output->adap); - } - break; - } - } -+ dvb_unregister_adapters(dev); - } - - /****************************************************************************/ - /****************************************************************************/ - --static int port_has_ci(struct ddb_port *port) -+static int port_has_cxd(struct ddb_port *port) - { - u8 val; - return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1; -@@ -1172,6 +1835,21 @@ - return 1; - } - -+static int port_has_stv0367(struct ddb_port *port) -+{ -+ u8 val; -+ -+ if (i2c_read_reg16(&port->i2c->adap, 0x1e, 0xf000, &val) < 0) -+ return 0; -+ if (val != 0x60) -+ return 0; -+ if (i2c_read_reg16(&port->i2c->adap, 0x1f, 0xf000, &val) < 0) -+ return 0; -+ if (val != 0x60) -+ return 0; -+ return 1; -+} -+ - static void ddb_port_probe(struct ddb_port *port) - { - struct ddb *dev = port->dev; -@@ -1179,62 +1857,92 @@ - - port->class = DDB_PORT_NONE; - -- if (port_has_ci(port)) { -+ if (port->nr > 1 && dev->info->type == DDB_OCTOPUS_CI) { -+ modname = "CI internal"; -+ port->class = DDB_PORT_CI; -+ port->type = DDB_CI_INTERNAL; -+ } else if (port_has_cxd(port)) { - modname = "CI"; - port->class = DDB_PORT_CI; -- ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); -+ port->type = DDB_CI_EXTERNAL_SONY; -+ ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING); - } else if (port_has_stv0900(port)) { - modname = "DUAL DVB-S2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBS_ST; -- ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); -+ ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); - } else if (port_has_stv0900_aa(port)) { - modname = "DUAL DVB-S2"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBS_ST_AA; -- ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); -+ ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); - } else if (port_has_drxks(port)) { - modname = "DUAL DVB-C/T"; - port->class = DDB_PORT_TUNER; - port->type = DDB_TUNER_DVBCT_TR; -- ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); -+ ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING); -+ } else if (port_has_stv0367(port)) { -+ modname = "DUAL DVB-C/T"; -+ port->class = DDB_PORT_TUNER; -+ port->type = DDB_TUNER_DVBCT_ST; -+ ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); -+ } else if (port->nr == ts_loop) { -+ modname = "TS LOOP"; -+ port->class = DDB_PORT_LOOP; -+ } -+ printk(KERN_INFO "Port %d (TAB %d): %s\n", port->nr, port->nr+1, modname); -+} -+ -+static void ddb_dma_init(struct ddb_dma *dma, int nr, void *io) -+{ -+ unsigned long priv = (unsigned long) io; -+ -+ dma->io = io; -+ dma->nr = nr; -+ spin_lock_init(&dma->lock); -+ init_waitqueue_head(&dma->wq); -+ if (nr & 8) { -+ tasklet_init(&dma->tasklet, output_tasklet, priv); -+ dma->num = OUTPUT_DMA_BUFS; -+ dma->size = OUTPUT_DMA_SIZE; -+ dma->div = OUTPUT_DMA_IRQ_DIV; -+ } else { -+ tasklet_init(&dma->tasklet, input_tasklet, priv); -+ dma->num = INPUT_DMA_BUFS; -+ dma->size = INPUT_DMA_SIZE; -+ dma->div = INPUT_DMA_IRQ_DIV; - } -- printk(KERN_INFO "Port %d (TAB %d): %s\n", -- port->nr, port->nr+1, modname); - } - --static void ddb_input_init(struct ddb_port *port, int nr) -+static void ddb_input_init(struct ddb_port *port, int nr, int pnr) - { - struct ddb *dev = port->dev; - struct ddb_input *input = &dev->input[nr]; - -+ port->input[pnr] = input; - input->nr = nr; - input->port = port; -- input->dma_buf_num = INPUT_DMA_BUFS; -- input->dma_buf_size = INPUT_DMA_SIZE; -- ddbwritel(0, TS_INPUT_CONTROL(nr)); -- ddbwritel(2, TS_INPUT_CONTROL(nr)); -- ddbwritel(0, TS_INPUT_CONTROL(nr)); -- ddbwritel(0, DMA_BUFFER_ACK(nr)); -- tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input); -- spin_lock_init(&input->lock); -- init_waitqueue_head(&input->wq); -+ input->dma = &dev->dma[nr]; -+ ddb_dma_init(input->dma, nr, (void *) input); -+ ddbwritel(dev, 0, TS_INPUT_CONTROL(nr)); -+ ddbwritel(dev, 2, TS_INPUT_CONTROL(nr)); -+ ddbwritel(dev, 0, TS_INPUT_CONTROL(nr)); -+ ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma->nr)); -+ input->dvb.adap = &dev->adap[input->nr]; - } - - static void ddb_output_init(struct ddb_port *port, int nr) - { - struct ddb *dev = port->dev; - struct ddb_output *output = &dev->output[nr]; -+ port->output = output; - output->nr = nr; - output->port = port; -- output->dma_buf_num = OUTPUT_DMA_BUFS; -- output->dma_buf_size = OUTPUT_DMA_SIZE; -- -- ddbwritel(0, TS_OUTPUT_CONTROL(nr)); -- ddbwritel(2, TS_OUTPUT_CONTROL(nr)); -- ddbwritel(0, TS_OUTPUT_CONTROL(nr)); -- tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output); -- init_waitqueue_head(&output->wq); -+ output->dma = &dev->dma[nr + 8]; -+ ddb_dma_init(output->dma, nr + 8, (void *) output); -+ ddbwritel(dev, 0, TS_OUTPUT_CONTROL(nr)); -+ ddbwritel(dev, 2, TS_OUTPUT_CONTROL(nr)); -+ ddbwritel(dev, 0, TS_OUTPUT_CONTROL(nr)); - } - - static void ddb_ports_init(struct ddb *dev) -@@ -1247,14 +1955,16 @@ - port->dev = dev; - port->nr = i; - port->i2c = &dev->i2c[i]; -- port->input[0] = &dev->input[2 * i]; -- port->input[1] = &dev->input[2 * i + 1]; -- port->output = &dev->output[i]; - - mutex_init(&port->i2c_gate_lock); - ddb_port_probe(port); -- ddb_input_init(port, 2 * i); -- ddb_input_init(port, 2 * i + 1); -+ if (i >= 2 && dev->info->type == DDB_OCTOPUS_CI) { -+ ddb_input_init(port, 2 + i, 0); -+ ddb_input_init(port, 4 + i, 1); -+ } else { -+ ddb_input_init(port, 2 * i, 0); -+ ddb_input_init(port, 2 * i + 1, 1); -+ } - ddb_output_init(port, i); - } - } -@@ -1267,9 +1977,12 @@ - for (i = 0; i < dev->info->port_num; i++) { - port = &dev->port[i]; - port->dev = dev; -- tasklet_kill(&port->input[0]->tasklet); -- tasklet_kill(&port->input[1]->tasklet); -- tasklet_kill(&port->output->tasklet); -+ if (port->input[0]) -+ tasklet_kill(&port->input[0]->dma->tasklet); -+ if (port->input[1]) -+ tasklet_kill(&port->input[1]->dma->tasklet); -+ if (port->output) -+ tasklet_kill(&port->output->dma->tasklet); - } - } - -@@ -1288,13 +2001,18 @@ - static irqreturn_t irq_handler(int irq, void *dev_id) - { - struct ddb *dev = (struct ddb *) dev_id; -- u32 s = ddbreadl(INTERRUPT_STATUS); -+ u32 s = ddbreadl(dev, INTERRUPT_STATUS); - - if (!s) - return IRQ_NONE; - - do { -- ddbwritel(s, INTERRUPT_ACK); -+ ddbwritel(dev, s, INTERRUPT_ACK); -+ -+ if (s & 0x0000000f) -+ dev->i2c_irq++; -+ if (s & 0x000fff00) -+ dev->ts_irq++; - - if (s & 0x00000001) - irq_handle_i2c(dev, 0); -@@ -1306,33 +2024,32 @@ - irq_handle_i2c(dev, 3); - - if (s & 0x00000100) -- tasklet_schedule(&dev->input[0].tasklet); -+ tasklet_schedule(&dev->dma[0].tasklet); - if (s & 0x00000200) -- tasklet_schedule(&dev->input[1].tasklet); -+ tasklet_schedule(&dev->dma[1].tasklet); - if (s & 0x00000400) -- tasklet_schedule(&dev->input[2].tasklet); -+ tasklet_schedule(&dev->dma[2].tasklet); - if (s & 0x00000800) -- tasklet_schedule(&dev->input[3].tasklet); -+ tasklet_schedule(&dev->dma[3].tasklet); - if (s & 0x00001000) -- tasklet_schedule(&dev->input[4].tasklet); -+ tasklet_schedule(&dev->dma[4].tasklet); - if (s & 0x00002000) -- tasklet_schedule(&dev->input[5].tasklet); -+ tasklet_schedule(&dev->dma[5].tasklet); - if (s & 0x00004000) -- tasklet_schedule(&dev->input[6].tasklet); -+ tasklet_schedule(&dev->dma[6].tasklet); - if (s & 0x00008000) -- tasklet_schedule(&dev->input[7].tasklet); -- -+ tasklet_schedule(&dev->dma[7].tasklet); - if (s & 0x00010000) -- tasklet_schedule(&dev->output[0].tasklet); -+ tasklet_schedule(&dev->dma[8].tasklet); - if (s & 0x00020000) -- tasklet_schedule(&dev->output[1].tasklet); -+ tasklet_schedule(&dev->dma[9].tasklet); - if (s & 0x00040000) -- tasklet_schedule(&dev->output[2].tasklet); -+ tasklet_schedule(&dev->dma[10].tasklet); - if (s & 0x00080000) -- tasklet_schedule(&dev->output[3].tasklet); -+ tasklet_schedule(&dev->dma[11].tasklet); - -- /* if (s & 0x000f0000) printk(KERN_DEBUG "%08x\n", istat); */ -- } while ((s = ddbreadl(INTERRUPT_STATUS))); -+ /* if (s & 0x000f0000) printk("%08x\n", istat); */ -+ } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); - - return IRQ_HANDLED; - } -@@ -1346,21 +2063,21 @@ - u32 data, shift; - - if (wlen > 4) -- ddbwritel(1, SPI_CONTROL); -+ ddbwritel(dev, 1, SPI_CONTROL); - while (wlen > 4) { - /* FIXME: check for big-endian */ - data = swab32(*(u32 *)wbuf); - wbuf += 4; - wlen -= 4; -- ddbwritel(data, SPI_DATA); -- while (ddbreadl(SPI_CONTROL) & 0x0004) -+ ddbwritel(dev, data, SPI_DATA); -+ while (ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; - } - - if (rlen) -- ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); -+ ddbwritel(dev, 0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); - else -- ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); -+ ddbwritel(dev, 0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); - - data = 0; - shift = ((4 - wlen) * 8); -@@ -1372,33 +2089,33 @@ - } - if (shift) - data <<= shift; -- ddbwritel(data, SPI_DATA); -- while (ddbreadl(SPI_CONTROL) & 0x0004) -+ ddbwritel(dev, data, SPI_DATA); -+ while (ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; - - if (!rlen) { -- ddbwritel(0, SPI_CONTROL); -+ ddbwritel(dev, 0, SPI_CONTROL); - return 0; - } - if (rlen > 4) -- ddbwritel(1, SPI_CONTROL); -+ ddbwritel(dev, 1, SPI_CONTROL); - - while (rlen > 4) { -- ddbwritel(0xffffffff, SPI_DATA); -- while (ddbreadl(SPI_CONTROL) & 0x0004) -+ ddbwritel(dev, 0xffffffff, SPI_DATA); -+ while (ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; -- data = ddbreadl(SPI_DATA); -+ data = ddbreadl(dev, SPI_DATA); - *(u32 *) rbuf = swab32(data); - rbuf += 4; - rlen -= 4; - } -- ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL); -- ddbwritel(0xffffffff, SPI_DATA); -- while (ddbreadl(SPI_CONTROL) & 0x0004) -+ ddbwritel(dev, 0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL); -+ ddbwritel(dev, 0xffffffff, SPI_DATA); -+ while (ddbreadl(dev, SPI_CONTROL) & 0x0004) - ; - -- data = ddbreadl(SPI_DATA); -- ddbwritel(0, SPI_CONTROL); -+ data = ddbreadl(dev, SPI_DATA); -+ ddbwritel(dev, 0, SPI_CONTROL); - - if (rlen < 4) - data <<= ((4 - rlen) * 8); -@@ -1421,14 +2138,21 @@ - __u32 read_len; - }; - -+struct ddb_gpio { -+ __u32 mask; -+ __u32 data; -+}; -+ -+ - #define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio) -+#define IOCTL_DDB_GPIO_IN _IOWR(DDB_MAGIC, 0x01, struct ddb_gpio) -+#define IOCTL_DDB_GPIO_OUT _IOWR(DDB_MAGIC, 0x02, struct ddb_gpio) - - #define DDB_NAME "ddbridge" - - static u32 ddb_num; --static struct ddb *ddbs[32]; --static struct class *ddb_class; - static int ddb_major; -+static DEFINE_MUTEX(ddb_mutex); - - static int ddb_open(struct inode *inode, struct file *file) - { -@@ -1470,6 +2194,16 @@ - return -EFAULT; - break; - } -+ case IOCTL_DDB_GPIO_OUT: -+ { -+ struct ddb_gpio gpio; -+ if (copy_from_user(&gpio, parg, sizeof(gpio))) -+ break; -+ ddbwritel(dev, gpio.mask, GPIO_DIRECTION); -+ ddbwritel(dev, gpio.data, GPIO_OUTPUT); -+ res = 0; -+ break; -+ } - default: - return -ENOTTY; - } -@@ -1481,41 +2215,248 @@ - .open = ddb_open, - }; - --static char *ddb_devnode(struct device *device, umode_t *mode) -+static char *ddb_devnode(struct device *device, mode_t *mode) - { - struct ddb *dev = dev_get_drvdata(device); - - return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr); - } - -+static ssize_t ports_show(struct device *device, struct device_attribute *attr, char *buf) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ -+ return sprintf(buf, "%d\n", dev->info->port_num); -+} -+ -+static ssize_t ts_irq_show(struct device *device, struct device_attribute *attr, char *buf) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ -+ return sprintf(buf, "%d\n", dev->ts_irq); -+} -+ -+static ssize_t i2c_irq_show(struct device *device, struct device_attribute *attr, char *buf) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ -+ return sprintf(buf, "%d\n", dev->i2c_irq); -+} -+ -+static char *class_name[] = { -+ "NONE", "CI", "TUNER", "LOOP" -+}; -+ -+static char *type_name[] = { -+ "NONE", "DVBS_ST", "DVBS_ST_AA", "DVBCT_TR", "DVBCT_ST", "INTERNAL", "CXD2099", -+}; -+ -+static ssize_t fan_show(struct device *device, struct device_attribute *attr, char *buf) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ u32 val; -+ -+ val = ddbreadl(dev, GPIO_OUTPUT) & 1; -+ return sprintf(buf, "%d\n", val); -+} -+ -+static ssize_t fan_store(struct device *device, struct device_attribute *d, -+ const char *buf, size_t count) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ unsigned val; -+ -+ if (sscanf(buf, "%u\n", &val) != 1) -+ return -EINVAL; -+ ddbwritel(dev, 1, GPIO_DIRECTION); -+ ddbwritel(dev, val & 1, GPIO_OUTPUT); -+ return count; -+} -+ -+static ssize_t temp_show(struct device *device, struct device_attribute *attr, char *buf) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ int temp; -+ u8 tmp[2]; -+ -+ if (!dev->info->temp_num) -+ return sprintf(buf, "no sensor\n"); -+ if (i2c_read_regs(&dev->i2c[0].adap, 0x48, 0, tmp, 2) < 0) -+ return sprintf(buf, "read_error\n"); -+ temp = (tmp[0] << 3) | (tmp[1] >> 5); -+ temp *= 125; -+ return sprintf(buf, "%d\n", temp); -+} -+ -+static ssize_t mod_show(struct device *device, struct device_attribute *attr, char *buf) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ int num = attr->attr.name[3] - 0x30; -+ -+ return sprintf(buf, "%s:%s\n", -+ class_name[dev->port[num].class], -+ type_name[dev->port[num].type]); -+} -+ -+static ssize_t led_show(struct device *device, struct device_attribute *attr, char *buf) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ int num = attr->attr.name[3] - 0x30; -+ -+ return sprintf(buf, "%d\n", dev->leds & (1 << num) ? 1 : 0); -+} -+ -+ -+static void ddb_set_led(struct ddb *dev, int num, int val) -+{ -+ if (!dev->info->led_num) -+ return; -+ switch (dev->port[num].class) { -+ case DDB_PORT_TUNER: -+ switch (dev->port[num].type) { -+ case DDB_TUNER_DVBS_ST: -+ printk(KERN_INFO "LED %d %d\n", num, val); -+ i2c_write_reg16(&dev->i2c[num].adap, -+ 0x69, 0xf14c, val ? 2 : 0); -+ break; -+ case DDB_TUNER_DVBCT_ST: -+ printk(KERN_INFO "LED %d %d\n", num, val); -+ i2c_write_reg16(&dev->i2c[num].adap, -+ 0x1f, 0xf00e, 0); -+ i2c_write_reg16(&dev->i2c[num].adap, -+ 0x1f, 0xf00f, val ? 1 : 0); -+ break; -+ } -+ break; -+ default: -+ break; -+ } -+} -+ -+static ssize_t led_store(struct device *device, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ int num = attr->attr.name[3] - 0x30; -+ unsigned val; -+ -+ if (sscanf(buf, "%u\n", &val) != 1) -+ return -EINVAL; -+ if (val) -+ dev->leds |= (1 << num); -+ else -+ dev->leds &= ~(1 << num); -+ ddb_set_led(dev, num, val); -+ return count; -+} -+ -+static ssize_t snr_show(struct device *device, struct device_attribute *attr, char *buf) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ char snr[32]; -+ int num = attr->attr.name[3] - 0x30; -+ -+ /* serial number at 0x100-0x11f */ -+ if (i2c_read_regs16(&dev->i2c[num].adap, 0x57, 0x100, snr, 32) < 0) -+ return sprintf(buf, "NO SNR\n"); -+ snr[31] = 0; /* in case it is not terminated on EEPROM */ -+ return sprintf(buf, "%s\n", snr); -+} -+ -+ -+static ssize_t snr_store(struct device *device, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ struct ddb *dev = dev_get_drvdata(device); -+ int num = attr->attr.name[3] - 0x30; -+ u8 snr[34] = { 0x01, 0x00 }; -+ -+ if (count > 31) -+ return -EINVAL; -+ memcpy(snr + 2, buf, count); -+ i2c_write(&dev->i2c[num].adap, 0x57, snr, 34); -+ return count; -+} -+ -+static ssize_t redirect_show(struct device *device, struct device_attribute *attr, char *buf) -+{ -+ return 0; -+} -+ -+static ssize_t redirect_store(struct device *device, struct device_attribute *attr, -+ const char *buf, size_t count) -+{ -+ unsigned int i, p; -+ int res; -+ -+ if (sscanf(buf, "%x %x\n", &i, &p) != 2) -+ return -EINVAL; -+ printk(KERN_INFO "redirect: %02x, %02x\n", i, p); -+ res = set_redirect(i, p); -+ if (res < 0) -+ return res; -+ return count; -+} -+ -+#define __ATTR_MRO(_name, _show) { \ -+ .attr = { .name = __stringify(_name), .mode = 0444 }, \ -+ .show = _show, \ -+} -+ -+struct device_attribute ddb_attrs[] = { -+ __ATTR_RO(ports), -+ __ATTR_RO(ts_irq), -+ __ATTR_RO(i2c_irq), -+ __ATTR_MRO(mod0, mod_show), -+ __ATTR_MRO(mod1, mod_show), -+ __ATTR_MRO(mod2, mod_show), -+ __ATTR_MRO(mod3, mod_show), -+ __ATTR_RO(temp), -+ __ATTR(fan, 0666, fan_show, fan_store), -+ __ATTR(led0, 0666, led_show, led_store), -+ __ATTR(led1, 0666, led_show, led_store), -+ __ATTR(led2, 0666, led_show, led_store), -+ __ATTR(led3, 0666, led_show, led_store), -+ __ATTR(snr0, 0666, snr_show, snr_store), -+ __ATTR(snr1, 0666, snr_show, snr_store), -+ __ATTR(snr2, 0666, snr_show, snr_store), -+ __ATTR(snr3, 0666, snr_show, snr_store), -+ __ATTR(redirect, 0666, redirect_show, redirect_store), -+ __ATTR_NULL -+}; -+ -+static struct class ddb_class = { -+ .name = "ddbridge", -+ .owner = THIS_MODULE, -+ .dev_attrs = ddb_attrs, -+ .devnode = ddb_devnode, -+}; -+ - static int ddb_class_create(void) - { - ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops); - if (ddb_major < 0) - return ddb_major; -- -- ddb_class = class_create(THIS_MODULE, DDB_NAME); -- if (IS_ERR(ddb_class)) { -- unregister_chrdev(ddb_major, DDB_NAME); -+ if (class_register(&ddb_class) < 0) - return -1; -- } -- ddb_class->devnode = ddb_devnode; - return 0; - } - - static void ddb_class_destroy(void) - { -- class_destroy(ddb_class); -+ class_unregister(&ddb_class); - unregister_chrdev(ddb_major, DDB_NAME); - } - - static int ddb_device_create(struct ddb *dev) - { -+ mutex_lock(&ddb_mutex); - dev->nr = ddb_num++; -- dev->ddb_dev = device_create(ddb_class, NULL, -+ ddbs[dev->nr] = dev; -+ mutex_unlock(&ddb_mutex); -+ dev->ddb_dev = device_create(&ddb_class, &dev->pdev->dev, - MKDEV(ddb_major, dev->nr), - dev, "ddbridge%d", dev->nr); -- ddbs[dev->nr] = dev; - if (IS_ERR(dev->ddb_dev)) - return -1; - return 0; -@@ -1523,10 +2464,9 @@ - - static void ddb_device_destroy(struct ddb *dev) - { -- ddb_num--; - if (IS_ERR(dev->ddb_dev)) - return; -- device_destroy(ddb_class, MKDEV(ddb_major, 0)); -+ device_destroy(&ddb_class, MKDEV(ddb_major, dev->nr)); - } - - -@@ -1549,7 +2489,7 @@ - ddb_ports_detach(dev); - ddb_i2c_release(dev); - -- ddbwritel(0, INTERRUPT_ENABLE); -+ ddbwritel(dev, 0, INTERRUPT_ENABLE); - free_irq(dev->pdev->irq, dev); - #ifdef CONFIG_PCI_MSI - if (dev->msi) -@@ -1564,7 +2504,6 @@ - pci_disable_device(pdev); - } - -- - static int __devinit ddb_probe(struct pci_dev *pdev, - const struct pci_device_id *id) - { -@@ -1575,10 +2514,9 @@ - if (pci_enable_device(pdev) < 0) - return -ENODEV; - -- dev = vmalloc(sizeof(struct ddb)); -+ dev = vzalloc(sizeof(struct ddb)); - if (dev == NULL) - return -ENOMEM; -- memset(dev, 0, sizeof(struct ddb)); - - dev->pdev = pdev; - pci_set_drvdata(pdev, dev); -@@ -1591,7 +2529,8 @@ - stat = -ENOMEM; - goto fail; - } -- printk(KERN_INFO "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4)); -+ printk(KERN_INFO "HW %08x REG %08x\n", -+ ddbreadl(dev, 0), ddbreadl(dev, 4)); - - #ifdef CONFIG_PCI_MSI - if (pci_msi_enabled()) -@@ -1607,11 +2546,11 @@ - irq_flag, "DDBridge", (void *) dev); - if (stat < 0) - goto fail1; -- ddbwritel(0, DMA_BASE_WRITE); -- ddbwritel(0, DMA_BASE_READ); -- ddbwritel(0xffffffff, INTERRUPT_ACK); -- ddbwritel(0xfff0f, INTERRUPT_ENABLE); -- ddbwritel(0, MSI1_ENABLE); -+ ddbwritel(dev, 0, DMA_BASE_WRITE); -+ ddbwritel(dev, 0, DMA_BASE_READ); -+ ddbwritel(dev, 0xffffffff, INTERRUPT_ACK); -+ ddbwritel(dev, 0x000fff0f, INTERRUPT_ENABLE); -+ ddbwritel(dev, 0, MSI1_ENABLE); - - if (ddb_i2c_init(dev) < 0) - goto fail1; -@@ -1622,7 +2561,13 @@ - } - if (ddb_ports_attach(dev) < 0) - goto fail3; -+ - ddb_device_create(dev); -+ -+ if (dev->info->fan_num) { -+ ddbwritel(dev, 1, GPIO_DIRECTION); -+ ddbwritel(dev, 1, GPIO_OUTPUT); -+ } - return 0; - - fail3: -@@ -1632,11 +2577,14 @@ - fail2: - printk(KERN_ERR "fail2\n"); - ddb_buffers_free(dev); -+ ddb_i2c_release(dev); - fail1: - printk(KERN_ERR "fail1\n"); -+ free_irq(dev->pdev->irq, dev); -+#ifdef CONFIG_PCI_MSI - if (dev->msi) - pci_disable_msi(dev->pdev); -- free_irq(dev->pdev->irq, dev); -+#endif - fail: - printk(KERN_ERR "fail\n"); - ddb_unmap(dev); -@@ -1658,23 +2606,71 @@ - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus DVB adapter", - .port_num = 4, -+ .i2c_num = 4, - }; - - static struct ddb_info ddb_octopus_le = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Octopus LE DVB adapter", - .port_num = 2, -+ .i2c_num = 2, -+}; -+ -+static struct ddb_info ddb_octopus_oem = { -+ .type = DDB_OCTOPUS, -+ .name = "Digital Devices Octopus OEM", -+ .port_num = 4, -+ .i2c_num = 4, -+ .led_num = 1, -+ .fan_num = 1, -+ .temp_num = 1, -+}; -+ -+static struct ddb_info ddb_octopus_mini = { -+ .type = DDB_OCTOPUS, -+ .name = "Digital Devices Octopus Mini", -+ .port_num = 4, -+ .i2c_num = 4, - }; - - static struct ddb_info ddb_v6 = { - .type = DDB_OCTOPUS, - .name = "Digital Devices Cine S2 V6 DVB adapter", - .port_num = 3, -+ .i2c_num = 3, -+}; -+ -+static struct ddb_info ddb_dvbct = { -+ .type = DDB_OCTOPUS, -+ .name = "Digital Devices DVBCT V6.1 DVB adapter", -+ .port_num = 3, -+ .i2c_num = 3, -+}; -+ -+static struct ddb_info ddb_satixS2v3 = { -+ .type = DDB_OCTOPUS, -+ .name = "Mystique SaTiX-S2 V3 DVB adapter", -+ .port_num = 3, -+ .i2c_num = 3, -+}; -+ -+static struct ddb_info ddb_ci = { -+ .type = DDB_OCTOPUS_CI, -+ .name = "Digital Devices Octopus CI", -+ .port_num = 4, -+ .i2c_num = 2, -+}; -+ -+static struct ddb_info ddb_cis = { -+ .type = DDB_OCTOPUS_CI, -+ .name = "Digital Devices Octopus CI single", -+ .port_num = 3, -+ .i2c_num = 2, - }; - - #define DDVID 0xdd01 /* Digital Devices Vendor ID */ - --#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \ -+#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \ - .vendor = _vend, .device = _dev, \ - .subvendor = _subvend, .subdevice = _subdev, \ - .driver_data = (unsigned long)&_driverdata } -@@ -1683,8 +2679,13 @@ - DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus), - DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus), - DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le), -- DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus), -+ DDB_ID(DDVID, 0x0003, DDVID, 0x0003, ddb_octopus_oem), -+ DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus_mini), - DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6), -+ DDB_ID(DDVID, 0x0003, DDVID, 0x0030, ddb_dvbct), -+ DDB_ID(DDVID, 0x0003, DDVID, 0xdb03, ddb_satixS2v3), -+ DDB_ID(DDVID, 0x0011, DDVID, 0x0040, ddb_ci), -+ DDB_ID(DDVID, 0x0011, DDVID, 0x0041, ddb_cis), - /* in case sub-ids got deleted in flash */ - DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none), - {0} -@@ -1696,16 +2697,21 @@ - .name = "DDBridge", - .id_table = ddb_id_tbl, - .probe = ddb_probe, -- .remove = __devexit_p(ddb_remove), -+ .remove = ddb_remove, - }; - - static __init int module_init_ddbridge(void) - { -+ int stat; -+ - printk(KERN_INFO "Digital Devices PCIE bridge driver, " - "Copyright (C) 2010-11 Digital Devices GmbH\n"); - if (ddb_class_create()) - return -1; -- return pci_register_driver(&ddb_pci_driver); -+ stat = pci_register_driver(&ddb_pci_driver); -+ if (stat < 0) -+ ddb_class_destroy(); -+ return stat; - } - - static __exit void module_exit_ddbridge(void) -@@ -1720,4 +2726,4 @@ - MODULE_DESCRIPTION("Digital Devices PCIe Bridge"); - MODULE_AUTHOR("Ralph Metzler"); - MODULE_LICENSE("GPL"); --MODULE_VERSION("0.5"); -+MODULE_VERSION("0.8"); -diff -Naur linux-3.6.8/drivers/media/dvb/ddbridge/ddbridge.h linux-3.6.8.patch/drivers/media/dvb/ddbridge/ddbridge.h ---- linux-3.6.8/drivers/media/dvb/ddbridge/ddbridge.h 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ddbridge/ddbridge.h 2012-12-03 08:41:17.000000000 +0100 -@@ -32,7 +32,10 @@ - #include - #include - #include -+#include -+#include - #include -+#include - - #include "dmxdev.h" - #include "dvbdev.h" -@@ -52,43 +55,53 @@ - int type; - #define DDB_NONE 0 - #define DDB_OCTOPUS 1 -+#define DDB_OCTOPUS_CI 2 - char *name; - int port_num; -- u32 port_type[DDB_MAX_PORT]; -+ int i2c_num; -+ int led_num; -+ int fan_num; -+ int temp_num; - }; - - /* DMA_SIZE MUST be divisible by 188 and 128 !!! */ - --#define INPUT_DMA_MAX_BUFS 32 /* hardware table limit */ -+#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_MAX_BUFS 32 - #define OUTPUT_DMA_BUFS 8 - #define OUTPUT_DMA_SIZE (128*47*21) -+#define OUTPUT_DMA_IRQ_DIV 1 - - struct ddb; - struct ddb_port; - --struct ddb_input { -- struct ddb_port *port; -+struct ddb_dma { -+ void *io; - u32 nr; -- int attached; -- -- dma_addr_t pbuf[INPUT_DMA_MAX_BUFS]; -- u8 *vbuf[INPUT_DMA_MAX_BUFS]; -- u32 dma_buf_num; -- u32 dma_buf_size; -+ dma_addr_t pbuf[DMA_MAX_BUFS]; -+ u8 *vbuf[DMA_MAX_BUFS]; -+ u32 num; -+ u32 size; -+ u32 div; -+ u32 bufreg; - - struct tasklet_struct tasklet; - spinlock_t lock; - wait_queue_head_t wq; - int running; - u32 stat; -+ u32 ctrl; - u32 cbuf; - u32 coff; -+}; - -- struct dvb_adapter adap; -+struct ddb_dvb { -+ struct dvb_adapter *adap; -+ int adap_registered; - struct dvb_device *dev; - struct dvb_frontend *fe; - struct dvb_frontend *fe2; -@@ -99,32 +112,36 @@ - struct dmx_frontend mem_frontend; - int users; - int (*gate_ctrl)(struct dvb_frontend *, int); -+ int attached; - }; - --struct ddb_output { -+struct ddb_ci { -+ struct dvb_ca_en50221 en; - struct ddb_port *port; - u32 nr; -- dma_addr_t pbuf[OUTPUT_DMA_MAX_BUFS]; -- u8 *vbuf[OUTPUT_DMA_MAX_BUFS]; -- u32 dma_buf_num; -- u32 dma_buf_size; -- struct tasklet_struct tasklet; -- spinlock_t lock; -- wait_queue_head_t wq; -- int running; -- u32 stat; -- u32 cbuf; -- u32 coff; -+}; - -- struct dvb_adapter adap; -- struct dvb_device *dev; -+ -+struct ddb_input { -+ struct ddb_port *port; -+ u32 nr; -+ struct ddb_dma *dma; -+ struct ddb_input *redirect; -+ -+ struct ddb_dvb dvb; -+}; -+ -+struct ddb_output { -+ struct ddb_port *port; -+ u32 nr; -+ struct ddb_dma *dma; -+ struct ddb_input *redirect; - }; - - struct ddb_i2c { - struct ddb *dev; - u32 nr; - struct i2c_adapter adap; -- struct i2c_adapter adap2; - u32 regs; - u32 rbuf; - u32 wbuf; -@@ -141,12 +158,15 @@ - #define DDB_PORT_NONE 0 - #define DDB_PORT_CI 1 - #define DDB_PORT_TUNER 2 -+#define DDB_PORT_LOOP 3 - u32 type; - #define DDB_TUNER_NONE 0 - #define DDB_TUNER_DVBS_ST 1 - #define DDB_TUNER_DVBS_ST_AA 2 --#define DDB_TUNER_DVBCT_TR 16 --#define DDB_TUNER_DVBCT_ST 17 -+#define DDB_TUNER_DVBCT_TR 3 -+#define DDB_TUNER_DVBCT_ST 4 -+#define DDB_CI_INTERNAL 5 -+#define DDB_CI_EXTERNAL_SONY 6 - u32 adr; - - struct ddb_input *input[2]; -@@ -161,25 +181,20 @@ - struct ddb_i2c i2c[DDB_MAX_I2C]; - struct ddb_input input[DDB_MAX_INPUT]; - struct ddb_output output[DDB_MAX_OUTPUT]; -+ struct dvb_adapter adap[DDB_MAX_INPUT]; -+ struct ddb_dma dma[DDB_MAX_INPUT + DDB_MAX_OUTPUT]; - - struct device *ddb_dev; -- int nr; -+ u32 nr; - u8 iobuf[1028]; - - struct ddb_info *info; - int msi; --}; -- --/****************************************************************************/ - --#define ddbwritel(_val, _adr) writel((_val), \ -- (char *) (dev->regs+(_adr))) --#define ddbreadl(_adr) readl((char *) (dev->regs+(_adr))) --#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *) \ -- (dev->regs+(_adr)), (_src), (_count)) --#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \ -- (dev->regs+(_adr)), (_count)) -+ u8 leds; - --/****************************************************************************/ -+ u32 ts_irq; -+ u32 i2c_irq; -+}; - - #endif -diff -Naur linux-3.6.8/drivers/media/dvb/ddbridge/ddbridge-regs.h linux-3.6.8.patch/drivers/media/dvb/ddbridge/ddbridge-regs.h ---- linux-3.6.8/drivers/media/dvb/ddbridge/ddbridge-regs.h 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ddbridge/ddbridge-regs.h 2012-12-03 08:41:17.000000000 +0100 -@@ -21,11 +21,12 @@ - * Or, point your browser to http://www.gnu.org/copyleft/gpl.html - */ - --/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */ -+/* DD-DVBBridgeV1.h 388 2011-07-13 20:47:08Z manfred */ - - /* Register Definitions */ - --#define CUR_REGISTERMAP_VERSION 0x10000 -+#define CUR_REGISTERMAP_VERSION 0x10003 -+#define CUR_REGISTERMAP_VERSION_CI 0x10000 - - #define HARDWARE_VERSION 0x00 - #define REGISTERMAP_VERSION 0x04 -@@ -36,8 +37,14 @@ - #define SPI_CONTROL 0x10 - #define SPI_DATA 0x14 - --/* ------------------------------------------------------------------------- */ -+/* -------------------------------------------------------------------------- */ -+/* GPIO */ -+ -+#define GPIO_OUTPUT 0x20 -+#define GPIO_INPUT 0x24 -+#define GPIO_DIRECTION 0x28 - -+/* -------------------------------------------------------------------------- */ - /* Interrupt controller */ - /* How many MSI's are available depends on HW (Min 2 max 8) */ - /* How many are usable also depends on Host platform */ -@@ -149,3 +156,46 @@ - #define DMA_BASE_ADDRESS_TABLE (0x2000) - #define DMA_BASE_ADDRESS_TABLE_ENTRIES (512) - -+/* -------------------------------------------------------------------------- */ -+/* CI Interface (only CI-Bridge) */ -+ -+#define CI_BASE (0x400) -+#define CI_CONTROL(i) (CI_BASE + (i) * 32 + 0x00) -+ -+#define CI_DO_ATTRIBUTE_RW(i) (CI_BASE + (i) * 32 + 0x04) -+#define CI_DO_IO_RW(i) (CI_BASE + (i) * 32 + 0x08) -+#define CI_READDATA(i) (CI_BASE + (i) * 32 + 0x0c) -+#define CI_DO_READ_ATTRIBUTES(i) (CI_BASE + (i) * 32 + 0x10) -+ -+#define CI_RESET_CAM (0x00000001) -+#define CI_POWER_ON (0x00000002) -+#define CI_ENABLE (0x00000004) -+#define CI_BLOCKIO_ENABLE (0x00000008) -+#define CI_BYPASS_DISABLE (0x00000010) -+#define CI_DISABLE_AUTO_OFF (0x00000020) -+ -+#define CI_CAM_READY (0x00010000) -+#define CI_CAM_DETECT (0x00020000) -+#define CI_READY (0x80000000) -+#define CI_BLOCKIO_ACTIVE (0x40000000) -+#define CI_BLOCKIO_RCVDATA (0x20000000) -+#define CI_BLOCKIO_SEND_PENDING (0x10000000) -+#define CI_BLOCKIO_SEND_COMPLETE (0x08000000) -+ -+#define CI_READ_CMD (0x40000000) -+#define CI_WRITE_CMD (0x80000000) -+ -+#define CI_BLOCKIO_SEND(i) (CI_BASE + (i) * 32 + 0x14) -+#define CI_BLOCKIO_RECEIVE(i) (CI_BASE + (i) * 32 + 0x18) -+ -+#define CI_BLOCKIO_SEND_COMMAND (0x80000000) -+#define CI_BLOCKIO_SEND_COMPLETE_ACK (0x40000000) -+#define CI_BLOCKIO_RCVDATA_ACK (0x40000000) -+ -+#define CI_BUFFER_BASE (0x3000) -+#define CI_BUFFER_SIZE (0x0800) -+#define CI_BLOCKIO_BUFFER_SIZE (CI_BUFFER_SIZE/2) -+ -+#define CI_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE) -+#define CI_BLOCKIO_RECEIVE_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE) -+#define CI_BLOCKIO_SEND_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE + CI_BLOCKIO_BUFFER_SIZE) -diff -Naur linux-3.6.8/drivers/media/dvb/ddbridge/Kconfig linux-3.6.8.patch/drivers/media/dvb/ddbridge/Kconfig ---- linux-3.6.8/drivers/media/dvb/ddbridge/Kconfig 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ddbridge/Kconfig 2012-12-03 08:41:17.000000000 +0100 -@@ -1,11 +1,14 @@ - config DVB_DDBRIDGE - tristate "Digital Devices bridge support" - depends on DVB_CORE && PCI && I2C -+ select DVB_CXD2099 - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_DRXK if !DVB_FE_CUSTOMISE - select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE -+ select DVB_STV0367DD if !DVB_FE_CUSTOMISE -+ select DVB_TDA18212DD if !DVB_FE_CUSTOMISE - ---help--- - Support for cards with the Digital Devices PCI express bridge: - - Octopus PCIe Bridge -@@ -14,5 +17,6 @@ - - DuoFlex S2 Octopus - - DuoFlex CT Octopus - - cineS2(v6) -+ - cineCT(v6) - - Say Y if you own such a card and want to use it. -diff -Naur linux-3.6.8/drivers/media/dvb/frontends/Kconfig linux-3.6.8.patch/drivers/media/dvb/frontends/Kconfig ---- linux-3.6.8/drivers/media/dvb/frontends/Kconfig 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/frontends/Kconfig 2012-12-03 08:53:41.676515316 +0100 -@@ -71,6 +71,24 @@ +diff -Naur linux-3.7.3/drivers/media/dvb-frontends/Kconfig linux-3.7.3.patch/drivers/media/dvb-frontends/Kconfig +--- linux-3.7.3/drivers/media/dvb-frontends/Kconfig 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/dvb-frontends/Kconfig 2013-01-20 01:04:02.687340217 +0100 +@@ -56,6 +56,24 @@ Say Y when you want to support this tuner. +config DVB_STV0367DD + tristate "STV 0367 (DD)" + depends on DVB_CORE && I2C -+ default m if DVB_FE_CUSTOMISE ++ default m if !MEDIA_SUBDRV_AUTOSELECT + help + STV 0367 DVB-C/T demodulator (Digital Devices driver). + @@ -2951,7 +17,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/frontends/Kconfig linux-3.6.8.patch/dri +config DVB_TDA18212DD + tristate "NXP TDA18212 silicon tuner (DD)" + depends on DVB_CORE && I2C -+ default m if DVB_FE_CUSTOMISE ++ default m if !MEDIA_SUBDRV_AUTOSELECT + help + NXP TDA18212 silicon tuner (Digital Devices driver). + @@ -2960,9 +26,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/frontends/Kconfig linux-3.6.8.patch/dri comment "DVB-S (satellite) frontends" depends on DVB_CORE -diff -Naur linux-3.6.8/drivers/media/dvb/frontends/Makefile linux-3.6.8.patch/drivers/media/dvb/frontends/Makefile ---- linux-3.6.8/drivers/media/dvb/frontends/Makefile 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/frontends/Makefile 2012-12-03 08:54:42.673022901 +0100 +diff -Naur linux-3.7.3/drivers/media/dvb-frontends/Makefile linux-3.7.3.patch/drivers/media/dvb-frontends/Makefile +--- linux-3.7.3/drivers/media/dvb-frontends/Makefile 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/dvb-frontends/Makefile 2013-01-20 01:04:17.874233780 +0100 @@ -95,6 +95,8 @@ obj-$(CONFIG_DVB_CXD2820R) += cxd2820r.o obj-$(CONFIG_DVB_DRXK) += drxk.o @@ -2972,9 +38,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/frontends/Makefile linux-3.6.8.patch/dr obj-$(CONFIG_DVB_IT913X_FE) += it913x-fe.o obj-$(CONFIG_DVB_A8293) += a8293.o obj-$(CONFIG_DVB_TDA10071) += tda10071.o -diff -Naur linux-3.6.8/drivers/media/dvb/frontends/stv0367dd.c linux-3.6.8.patch/drivers/media/dvb/frontends/stv0367dd.c ---- linux-3.6.8/drivers/media/dvb/frontends/stv0367dd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/frontends/stv0367dd.c 2012-12-03 09:05:24.906890534 +0100 +diff -Naur linux-3.7.3/drivers/media/dvb-frontends/stv0367dd.c linux-3.7.3.patch/drivers/media/dvb-frontends/stv0367dd.c +--- linux-3.7.3/drivers/media/dvb-frontends/stv0367dd.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/dvb-frontends/stv0367dd.c 2013-01-20 01:04:17.876233766 +0100 @@ -0,0 +1,2269 @@ +/* + * stv0367dd: STV0367 DVB-C/T demodulator driver @@ -5245,9 +2311,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/frontends/stv0367dd.c linux-3.6.8.patch + + + -diff -Naur linux-3.6.8/drivers/media/dvb/frontends/stv0367dd.h linux-3.6.8.patch/drivers/media/dvb/frontends/stv0367dd.h ---- linux-3.6.8/drivers/media/dvb/frontends/stv0367dd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/frontends/stv0367dd.h 2012-12-03 08:41:17.000000000 +0100 +diff -Naur linux-3.7.3/drivers/media/dvb-frontends/stv0367dd.h linux-3.7.3.patch/drivers/media/dvb-frontends/stv0367dd.h +--- linux-3.7.3/drivers/media/dvb-frontends/stv0367dd.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/dvb-frontends/stv0367dd.h 2013-01-20 01:04:17.877233760 +0100 @@ -0,0 +1,17 @@ +#ifndef _STV0367DD_H_ +#define _STV0367DD_H_ @@ -5266,9 +2332,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/frontends/stv0367dd.h linux-3.6.8.patch + struct stv0367_cfg *cfg, + struct dvb_frontend **fe_t); +#endif -diff -Naur linux-3.6.8/drivers/media/dvb/frontends/stv0367dd_regs.h linux-3.6.8.patch/drivers/media/dvb/frontends/stv0367dd_regs.h ---- linux-3.6.8/drivers/media/dvb/frontends/stv0367dd_regs.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/frontends/stv0367dd_regs.h 2012-12-03 08:41:17.000000000 +0100 +diff -Naur linux-3.7.3/drivers/media/dvb-frontends/stv0367dd_regs.h linux-3.7.3.patch/drivers/media/dvb-frontends/stv0367dd_regs.h +--- linux-3.7.3/drivers/media/dvb-frontends/stv0367dd_regs.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/dvb-frontends/stv0367dd_regs.h 2013-01-20 01:04:17.880233740 +0100 @@ -0,0 +1,3431 @@ +// @DVB-C/DVB-T STMicroelectronics STV0367 register defintions +// Author Manfred Völkel, Februar 2011 @@ -8701,9 +5767,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/frontends/stv0367dd_regs.h linux-3.6.8. +#define R367_QAM_T_O_ID_3 0xF4D3 +#define F367_QAM_TS_ID_I_H 0xF4D300FF + -diff -Naur linux-3.6.8/drivers/media/dvb/frontends/tda18212dd.c linux-3.6.8.patch/drivers/media/dvb/frontends/tda18212dd.c ---- linux-3.6.8/drivers/media/dvb/frontends/tda18212dd.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/frontends/tda18212dd.c 2012-12-03 09:05:08.956017665 +0100 +diff -Naur linux-3.7.3/drivers/media/dvb-frontends/tda18212dd.c linux-3.7.3.patch/drivers/media/dvb-frontends/tda18212dd.c +--- linux-3.7.3/drivers/media/dvb-frontends/tda18212dd.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/dvb-frontends/tda18212dd.c 2013-01-20 01:04:17.881233733 +0100 @@ -0,0 +1,906 @@ +/* + * tda18212: Driver for the TDA18212 tuner @@ -9611,37 +6677,2958 @@ diff -Naur linux-3.6.8/drivers/media/dvb/frontends/tda18212dd.c linux-3.6.8.patc + * c-basic-offset: 8 + * End: + */ -diff -Naur linux-3.6.8/drivers/media/dvb/frontends/tda18212dd.h linux-3.6.8.patch/drivers/media/dvb/frontends/tda18212dd.h ---- linux-3.6.8/drivers/media/dvb/frontends/tda18212dd.h 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/frontends/tda18212dd.h 2012-12-03 08:41:17.000000000 +0100 +diff -Naur linux-3.7.3/drivers/media/dvb-frontends/tda18212dd.h linux-3.7.3.patch/drivers/media/dvb-frontends/tda18212dd.h +--- linux-3.7.3/drivers/media/dvb-frontends/tda18212dd.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/dvb-frontends/tda18212dd.h 2013-01-20 01:04:17.881233733 +0100 @@ -0,0 +1,5 @@ +#ifndef _TDA18212DD_H_ +#define _TDA18212DD_H_ +struct dvb_frontend *tda18212dd_attach(struct dvb_frontend *fe, + struct i2c_adapter *i2c, u8 adr); +#endif -diff -Naur linux-3.6.8/drivers/media/dvb/ngene/Kconfig linux-3.6.8.patch/drivers/media/dvb/ngene/Kconfig ---- linux-3.6.8/drivers/media/dvb/ngene/Kconfig 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ngene/Kconfig 2012-12-03 08:41:17.000000000 +0100 -@@ -1,12 +1,15 @@ +diff -Naur linux-3.7.3/drivers/media/pci/ddbridge/ddbridge-core.c linux-3.7.3.patch/drivers/media/pci/ddbridge/ddbridge-core.c +--- linux-3.7.3/drivers/media/pci/ddbridge/ddbridge-core.c 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ddbridge/ddbridge-core.c 2013-01-20 01:27:14.359676005 +0100 +@@ -31,11 +31,11 @@ + #include + #include + #include ++#include + #include + #include + #include + #include "ddbridge.h" +- + #include "ddbridge-regs.h" + + #include "tda18271c2dd.h" +@@ -43,14 +43,60 @@ + #include "stv090x.h" + #include "lnbh24.h" + #include "drxk.h" ++#if 0 ++#include "stv0367.h" ++#else ++#include "stv0367dd.h" ++#endif ++#if 0 ++#include "tda18212.h" ++#else ++#include "tda18212dd.h" ++#endif ++ ++static int adapter_alloc; ++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 ts_loop = -1; ++module_param(ts_loop, int, 0444); ++MODULE_PARM_DESC(ts_loop, "TS in/out on port ts_loop"); + + DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); + ++static struct ddb *ddbs[32]; ++ + /* MSI had problems with lost interrupts, fixed but needs testing */ +-#undef CONFIG_PCI_MSI ++/* #undef CONFIG_PCI_MSI */ ++ ++/******************************************************************************/ ++ ++static inline void ddbwritel(struct ddb *dev, u32 val, u32 adr) ++{ ++ writel(val, (char *) (dev->regs+(adr))); ++} ++ ++static inline u32 ddbreadl(struct ddb *dev, u32 adr) ++{ ++ return readl((char *) (dev->regs+(adr))); ++} ++ ++#define ddbcpyto(_dev, _adr, _src, _count) memcpy_toio((char *) \ ++ (_dev->regs + (_adr)), (_src), (_count)) ++ ++#define ddbcpyfrom(_dev, _dst, _adr, _count) memcpy_fromio((_dst), (char *) \ ++ (_dev->regs + (_adr)), (_count)) ++ + + /******************************************************************************/ + ++static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) ++{ ++ struct i2c_msg msg = {.addr = adr, .flags = 0, .buf = data, .len = len}; ++ ++ return (i2c_transfer(adap, &msg, 1) == 1) ? 0 : -1; ++} ++ + static int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val) + { + struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD, +@@ -58,10 +104,31 @@ + return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1; + } + ++static int i2c_read_regs(struct i2c_adapter *adapter, ++ u8 adr, u8 reg, u8 *val, u8 len) ++{ ++ struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, ++ .buf = ®, .len = 1}, ++ {.addr = adr, .flags = I2C_M_RD, ++ .buf = val, .len = len } }; ++ return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; ++} ++ ++static int i2c_read_regs16(struct i2c_adapter *adapter, ++ u8 adr, u16 reg, u8 *val, u8 len) ++{ ++ u8 reg16[2] = { reg >> 8, reg }; ++ struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, ++ .buf = (u8 *)®16, .len = 2}, ++ {.addr = adr, .flags = I2C_M_RD, ++ .buf = val, .len = len } }; ++ return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; ++} ++ + static int i2c_read_reg(struct i2c_adapter *adapter, u8 adr, u8 reg, u8 *val) + { + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, +- .buf = ®, .len = 1 }, ++ .buf = ®, .len = 1}, + {.addr = adr, .flags = I2C_M_RD, + .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; +@@ -70,14 +137,22 @@ + static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr, + u16 reg, u8 *val) + { +- u8 msg[2] = {reg>>8, reg&0xff}; ++ u8 msg[2] = {reg >> 8, reg & 0xff}; + struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0, + .buf = msg, .len = 2}, + {.addr = adr, .flags = I2C_M_RD, +- .buf = val, .len = 1} }; ++ .buf = val, .len = 1 } }; + return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1; + } + ++static int i2c_write_reg16(struct i2c_adapter *adap, u8 adr, ++ u16 reg, u8 val) ++{ ++ u8 msg[3] = {reg >> 8, reg & 0xff, val}; ++ ++ return i2c_write(adap, adr, msg, 3); ++} ++ + static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) + { + struct ddb *dev = i2c->dev; +@@ -85,18 +160,18 @@ + u32 val; + + i2c->done = 0; +- ddbwritel((adr << 9) | cmd, i2c->regs + I2C_COMMAND); ++ ddbwritel(dev, (adr << 9) | cmd, i2c->regs + I2C_COMMAND); + stat = wait_event_timeout(i2c->wq, i2c->done == 1, HZ); + if (stat <= 0) { + printk(KERN_ERR "I2C timeout\n"); + { /* MSI debugging*/ +- u32 istat = ddbreadl(INTERRUPT_STATUS); ++ u32 istat = ddbreadl(dev, INTERRUPT_STATUS); + printk(KERN_ERR "IRS %08x\n", istat); +- ddbwritel(istat, INTERRUPT_ACK); ++ ddbwritel(dev, istat, INTERRUPT_ACK); + } + return -EIO; + } +- val = ddbreadl(i2c->regs+I2C_COMMAND); ++ val = ddbreadl(dev, i2c->regs+I2C_COMMAND); + if (val & 0x70000) + return -EIO; + return 0; +@@ -105,7 +180,7 @@ + static int ddb_i2c_master_xfer(struct i2c_adapter *adapter, + struct i2c_msg msg[], int num) + { +- struct ddb_i2c *i2c = (struct ddb_i2c *)i2c_get_adapdata(adapter); ++ struct ddb_i2c *i2c = (struct ddb_i2c *) i2c_get_adapdata(adapter); + struct ddb *dev = i2c->dev; + u8 addr = 0; + +@@ -116,8 +191,8 @@ + !(msg[0].flags & I2C_M_RD)) { + memcpy_toio(dev->regs + I2C_TASKMEM_BASE + i2c->wbuf, + msg[0].buf, msg[0].len); +- ddbwritel(msg[0].len|(msg[1].len << 16), +- i2c->regs+I2C_TASKLENGTH); ++ ddbwritel(dev, msg[0].len|(msg[1].len << 16), ++ i2c->regs + I2C_TASKLENGTH); + if (!ddb_i2c_cmd(i2c, addr, 1)) { + memcpy_fromio(msg[1].buf, + dev->regs + I2C_TASKMEM_BASE + i2c->rbuf, +@@ -125,17 +200,16 @@ + return num; + } + } +- + if (num == 1 && !(msg[0].flags & I2C_M_RD)) { +- ddbcpyto(I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len); +- ddbwritel(msg[0].len, i2c->regs + I2C_TASKLENGTH); ++ ddbcpyto(dev, I2C_TASKMEM_BASE + i2c->wbuf, msg[0].buf, msg[0].len); ++ ddbwritel(dev, msg[0].len, i2c->regs + I2C_TASKLENGTH); + if (!ddb_i2c_cmd(i2c, addr, 2)) + return num; + } + if (num == 1 && (msg[0].flags & I2C_M_RD)) { +- ddbwritel(msg[0].len << 16, i2c->regs + I2C_TASKLENGTH); ++ ddbwritel(dev, msg[0].len << 16, i2c->regs + I2C_TASKLENGTH); + if (!ddb_i2c_cmd(i2c, addr, 3)) { +- ddbcpyfrom(msg[0].buf, ++ ddbcpyfrom(dev, msg[0].buf, + I2C_TASKMEM_BASE + i2c->rbuf, msg[0].len); + return num; + } +@@ -160,7 +234,7 @@ + struct ddb_i2c *i2c; + struct i2c_adapter *adap; + +- for (i = 0; i < dev->info->port_num; i++) { ++ for (i = 0; i < dev->info->i2c_num; i++) { + i2c = &dev->i2c[i]; + adap = &i2c->adap; + i2c_del_adapter(adap); +@@ -173,15 +247,15 @@ + struct ddb_i2c *i2c; + struct i2c_adapter *adap; + +- for (i = 0; i < dev->info->port_num; i++) { ++ for (i = 0; i < dev->info->i2c_num; i++) { + i2c = &dev->i2c[i]; + i2c->dev = dev; + i2c->nr = i; + i2c->wbuf = i * (I2C_TASKMEM_SIZE / 4); + i2c->rbuf = i2c->wbuf + (I2C_TASKMEM_SIZE / 8); + i2c->regs = 0x80 + i * 0x20; +- ddbwritel(I2C_SPEED_100, i2c->regs + I2C_TIMING); +- ddbwritel((i2c->rbuf << 16) | i2c->wbuf, ++ ddbwritel(dev, I2C_SPEED_100, i2c->regs + I2C_TIMING); ++ ddbwritel(dev, (i2c->rbuf << 16) | i2c->wbuf, + i2c->regs + I2C_TASKADDRESS); + init_waitqueue_head(&i2c->wq); + +@@ -216,69 +290,94 @@ + /******************************************************************************/ + /******************************************************************************/ + +-#if 0 +-static void set_table(struct ddb *dev, u32 off, +- dma_addr_t *pbuf, u32 num) ++static void ddb_set_dma_table(struct ddb *dev, struct ddb_dma *dma) + { + u32 i, base; + u64 mem; + +- base = DMA_BASE_ADDRESS_TABLE + off; +- for (i = 0; i < num; i++) { +- mem = pbuf[i]; +- ddbwritel(mem & 0xffffffff, base + i * 8); +- ddbwritel(mem >> 32, base + i * 8 + 4); ++ if (!dma) ++ return; ++ base = DMA_BASE_ADDRESS_TABLE + dma->nr * 0x100; ++ for (i = 0; i < dma->num; i++) { ++ mem = dma->pbuf[i]; ++ ddbwritel(dev, mem & 0xffffffff, base + i * 8); ++ ddbwritel(dev, mem >> 32, base + i * 8 + 4); + } ++ dma->bufreg = (dma->div << 16) | ++ ((dma->num & 0x1f) << 11) | ++ ((dma->size >> 7) & 0x7ff); + } +-#endif + +-static void ddb_address_table(struct ddb *dev) ++static void ddb_set_dma_tables(struct ddb *dev) + { +- u32 i, j, base; +- u64 mem; +- dma_addr_t *pbuf; ++ u32 i; + +- for (i = 0; i < dev->info->port_num * 2; i++) { +- base = DMA_BASE_ADDRESS_TABLE + i * 0x100; +- pbuf = dev->input[i].pbuf; +- for (j = 0; j < dev->input[i].dma_buf_num; j++) { +- mem = pbuf[j]; +- ddbwritel(mem & 0xffffffff, base + j * 8); +- ddbwritel(mem >> 32, base + j * 8 + 4); +- } +- } +- for (i = 0; i < dev->info->port_num; i++) { +- base = DMA_BASE_ADDRESS_TABLE + 0x800 + i * 0x100; +- pbuf = dev->output[i].pbuf; +- for (j = 0; j < dev->output[i].dma_buf_num; j++) { +- mem = pbuf[j]; +- ddbwritel(mem & 0xffffffff, base + j * 8); +- ddbwritel(mem >> 32, base + j * 8 + 4); +- } +- } ++ for (i = 0; i < dev->info->port_num * 2; i++) ++ ddb_set_dma_table(dev, dev->input[i].dma); ++ for (i = 0; i < dev->info->port_num; i++) ++ ddb_set_dma_table(dev, dev->output[i].dma); + } + +-static void io_free(struct pci_dev *pdev, u8 **vbuf, +- dma_addr_t *pbuf, u32 size, int num) ++static void dma_free(struct pci_dev *pdev, struct ddb_dma *dma) + { + int i; + +- for (i = 0; i < num; i++) { +- if (vbuf[i]) { +- pci_free_consistent(pdev, size, vbuf[i], pbuf[i]); +- vbuf[i] = 0; ++ if (!dma) ++ return; ++ for (i = 0; i < dma->num; i++) { ++ if (dma->vbuf[i]) { ++ pci_free_consistent(pdev, dma->size, ++ dma->vbuf[i], dma->pbuf[i]); ++ dma->vbuf[i] = 0; + } + } + } + +-static int io_alloc(struct pci_dev *pdev, u8 **vbuf, +- dma_addr_t *pbuf, u32 size, int num) ++static void ddb_redirect_dma(struct ddb *dev, ++ struct ddb_dma *sdma, ++ struct ddb_dma *ddma) ++{ ++ u32 i, base; ++ u64 mem; ++ ++ sdma->bufreg = ddma->bufreg; ++ base = DMA_BASE_ADDRESS_TABLE + sdma->nr * 0x100; ++ for (i = 0; i < ddma->num; i++) { ++ mem = ddma->pbuf[i]; ++ ddbwritel(dev, mem & 0xffffffff, base + i * 8); ++ ddbwritel(dev, mem >> 32, base + i * 8 + 4); ++ } ++} ++ ++static void ddb_unredirect(struct ddb_port *port) ++{ ++ struct ddb_input *ored, *ired; ++ ++ ored = port->output->redirect; ++ ired = port->input[0]->redirect; ++ ++ if (!ored || !ired) ++ return; ++ if (ired->port->output->redirect == port->input[0]) { ++ ired->port->output->redirect = ored; ++ ddb_set_dma_table(port->dev, port->input[0]->dma); ++ ddb_redirect_dma(ored->port->dev, ored->dma, ired->port->output->dma); ++ } else ++ ddb_set_dma_table(ored->port->dev, ored->dma); ++ ored->redirect = ired; ++ port->input[0]->redirect = 0; ++ port->output->redirect = 0; ++} ++ ++static int dma_alloc(struct pci_dev *pdev, struct ddb_dma *dma) + { + int i; + +- for (i = 0; i < num; i++) { +- vbuf[i] = pci_alloc_consistent(pdev, size, &pbuf[i]); +- if (!vbuf[i]) ++ if (!dma) ++ return 0; ++ for (i = 0; i < dma->num; i++) { ++ dma->vbuf[i] = pci_alloc_consistent(pdev, dma->size, &dma->pbuf[i]); ++ if (!dma->vbuf[i]) + return -ENOMEM; + } + return 0; +@@ -293,34 +392,23 @@ + port = &dev->port[i]; + switch (port->class) { + case DDB_PORT_TUNER: +- if (io_alloc(dev->pdev, port->input[0]->vbuf, +- port->input[0]->pbuf, +- port->input[0]->dma_buf_size, +- port->input[0]->dma_buf_num) < 0) ++ if (dma_alloc(dev->pdev, port->input[0]->dma) < 0) + return -1; +- if (io_alloc(dev->pdev, port->input[1]->vbuf, +- port->input[1]->pbuf, +- port->input[1]->dma_buf_size, +- port->input[1]->dma_buf_num) < 0) ++ if (dma_alloc(dev->pdev, port->input[1]->dma) < 0) + return -1; + break; + case DDB_PORT_CI: +- if (io_alloc(dev->pdev, port->input[0]->vbuf, +- port->input[0]->pbuf, +- port->input[0]->dma_buf_size, +- port->input[0]->dma_buf_num) < 0) ++ case DDB_PORT_LOOP: ++ if (dma_alloc(dev->pdev, port->input[0]->dma) < 0) + return -1; +- if (io_alloc(dev->pdev, port->output->vbuf, +- port->output->pbuf, +- port->output->dma_buf_size, +- port->output->dma_buf_num) < 0) ++ if (dma_alloc(dev->pdev, port->output->dma) < 0) + return -1; + break; + default: + break; + } + } +- ddb_address_table(dev); ++ ddb_set_dma_tables(dev); + return 0; + } + +@@ -331,18 +419,11 @@ + + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; +- io_free(dev->pdev, port->input[0]->vbuf, +- port->input[0]->pbuf, +- port->input[0]->dma_buf_size, +- port->input[0]->dma_buf_num); +- io_free(dev->pdev, port->input[1]->vbuf, +- port->input[1]->pbuf, +- port->input[1]->dma_buf_size, +- port->input[1]->dma_buf_num); +- io_free(dev->pdev, port->output->vbuf, +- port->output->pbuf, +- port->output->dma_buf_size, +- port->output->dma_buf_num); ++ ++ ddb_unredirect(port); ++ dma_free(dev->pdev, port->input[0]->dma); ++ dma_free(dev->pdev, port->input[1]->dma); ++ dma_free(dev->pdev, port->output->dma); + } + } + +@@ -350,90 +431,116 @@ + { + struct ddb *dev = input->port->dev; + +- spin_lock_irq(&input->lock); +- input->cbuf = 0; +- input->coff = 0; ++ spin_lock_irq(&input->dma->lock); ++ input->dma->cbuf = 0; ++ input->dma->coff = 0; + + /* reset */ +- ddbwritel(0, TS_INPUT_CONTROL(input->nr)); +- ddbwritel(2, TS_INPUT_CONTROL(input->nr)); +- ddbwritel(0, TS_INPUT_CONTROL(input->nr)); +- +- ddbwritel((1 << 16) | +- (input->dma_buf_num << 11) | +- (input->dma_buf_size >> 7), +- DMA_BUFFER_SIZE(input->nr)); +- ddbwritel(0, DMA_BUFFER_ACK(input->nr)); +- +- ddbwritel(1, DMA_BASE_WRITE); +- ddbwritel(3, DMA_BUFFER_CONTROL(input->nr)); +- ddbwritel(9, TS_INPUT_CONTROL(input->nr)); +- input->running = 1; +- spin_unlock_irq(&input->lock); ++ ddbwritel(dev, 0, TS_INPUT_CONTROL(input->nr)); ++ ddbwritel(dev, 2, TS_INPUT_CONTROL(input->nr)); ++ ddbwritel(dev, 0, TS_INPUT_CONTROL(input->nr)); ++ ++ ddbwritel(dev, input->dma->bufreg, DMA_BUFFER_SIZE(input->dma->nr)); ++ ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma->nr)); ++ ++ ddbwritel(dev, 1, DMA_BASE_WRITE); ++ ddbwritel(dev, 3, DMA_BUFFER_CONTROL(input->dma->nr)); ++ ddbwritel(dev, 9, TS_INPUT_CONTROL(input->nr)); ++ input->dma->running = 1; ++ spin_unlock_irq(&input->dma->lock); ++ /* printk(KERN_INFO "input_start %d\n", input->nr); */ + } + + static void ddb_input_stop(struct ddb_input *input) + { + struct ddb *dev = input->port->dev; + +- spin_lock_irq(&input->lock); +- ddbwritel(0, TS_INPUT_CONTROL(input->nr)); +- ddbwritel(0, DMA_BUFFER_CONTROL(input->nr)); +- input->running = 0; +- spin_unlock_irq(&input->lock); ++ spin_lock_irq(&input->dma->lock); ++ ddbwritel(dev, 0, TS_INPUT_CONTROL(input->nr)); ++ ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma->nr)); ++ input->dma->running = 0; ++ spin_unlock_irq(&input->dma->lock); + } + + static void ddb_output_start(struct ddb_output *output) + { + struct ddb *dev = output->port->dev; + +- spin_lock_irq(&output->lock); +- output->cbuf = 0; +- output->coff = 0; +- ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); +- ddbwritel(2, TS_OUTPUT_CONTROL(output->nr)); +- ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); +- ddbwritel(0x3c, TS_OUTPUT_CONTROL(output->nr)); +- ddbwritel((1 << 16) | +- (output->dma_buf_num << 11) | +- (output->dma_buf_size >> 7), +- DMA_BUFFER_SIZE(output->nr + 8)); +- ddbwritel(0, DMA_BUFFER_ACK(output->nr + 8)); +- +- ddbwritel(1, DMA_BASE_READ); +- ddbwritel(3, DMA_BUFFER_CONTROL(output->nr + 8)); +- /* ddbwritel(0xbd, TS_OUTPUT_CONTROL(output->nr)); */ +- ddbwritel(0x1d, TS_OUTPUT_CONTROL(output->nr)); +- output->running = 1; +- spin_unlock_irq(&output->lock); ++ spin_lock_irq(&output->dma->lock); ++ output->dma->cbuf = 0; ++ output->dma->coff = 0; ++ ddbwritel(dev, 0, TS_OUTPUT_CONTROL(output->nr)); ++ ddbwritel(dev, 2, TS_OUTPUT_CONTROL(output->nr)); ++ ddbwritel(dev, 0, TS_OUTPUT_CONTROL(output->nr)); ++ ddbwritel(dev, 0x3c, TS_OUTPUT_CONTROL(output->nr)); ++ ddbwritel(dev, output->dma->bufreg, DMA_BUFFER_SIZE(output->dma->nr)); ++ ddbwritel(dev, 0, DMA_BUFFER_ACK(output->dma->nr)); ++ ++ ddbwritel(dev, 1, DMA_BASE_READ); ++ ddbwritel(dev, 3, DMA_BUFFER_CONTROL(output->dma->nr)); ++ if (output->port->input[0]->port->class == DDB_PORT_LOOP) ++ ddbwritel(dev, 0x05, TS_OUTPUT_CONTROL(output->nr)); ++ else ++ ddbwritel(dev, 0x1d, TS_OUTPUT_CONTROL(output->nr)); ++ output->dma->running = 1; ++ spin_unlock_irq(&output->dma->lock); ++ /* printk(KERN_INFO "output_start %d\n", output->nr); */ ++} ++ ++#if 0 ++static void ddb_input_start_all(struct ddb_input *input) ++{ ++ struct ddb_input *next; ++ ++ ddb_input_start(input); ++ while ((next = input->redirect) && ++ next != input) { ++ ddb_input_start(next); ++ ddb_output_start(next->port->output); ++ } + } ++#endif + + static void ddb_output_stop(struct ddb_output *output) + { + struct ddb *dev = output->port->dev; + +- spin_lock_irq(&output->lock); +- ddbwritel(0, TS_OUTPUT_CONTROL(output->nr)); +- ddbwritel(0, DMA_BUFFER_CONTROL(output->nr + 8)); +- output->running = 0; +- spin_unlock_irq(&output->lock); ++ spin_lock_irq(&output->dma->lock); ++ ddbwritel(dev, 0, TS_OUTPUT_CONTROL(output->nr)); ++ ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma->nr)); ++ output->dma->running = 0; ++ spin_unlock_irq(&output->dma->lock); ++} ++ ++#if 0 ++static void ddb_input_stop_all(struct ddb_input *input) ++{ ++ struct ddb_input *next; ++ ++ ddb_input_stop(input); ++ while ((next = input->redirect) && ++ next != input) { ++ ddb_input_stop(next); ++ ddb_output_stop(next->port->output); ++ } + } ++#endif + + static u32 ddb_output_free(struct ddb_output *output) + { +- u32 idx, off, stat = output->stat; ++ u32 idx, off, stat = output->dma->stat; + s32 diff; + + idx = (stat >> 11) & 0x1f; + off = (stat & 0x7ff) << 7; + +- if (output->cbuf != idx) { +- if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && +- (output->dma_buf_size - output->coff <= 188)) ++ if (output->dma->cbuf != idx) { ++ if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && ++ (output->dma->size - output->dma->coff <= 188)) + return 0; + return 188; + } +- diff = off - output->coff; ++ diff = off - output->dma->coff; + if (diff <= 0 || diff > 188) + return 188; + return 0; +@@ -443,24 +550,24 @@ + const u8 *buf, size_t count) + { + struct ddb *dev = output->port->dev; +- u32 idx, off, stat = output->stat; ++ u32 idx, off, stat = output->dma->stat; + u32 left = count, len; + + idx = (stat >> 11) & 0x1f; + off = (stat & 0x7ff) << 7; + + while (left) { +- len = output->dma_buf_size - output->coff; +- if ((((output->cbuf + 1) % output->dma_buf_num) == idx) && ++ len = output->dma->size - output->dma->coff; ++ if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && + (off == 0)) { + if (len <= 188) + break; + len -= 188; + } +- if (output->cbuf == idx) { +- if (off > output->coff) { ++ if (output->dma->cbuf == idx) { ++ if (off > output->dma->coff) { + #if 1 +- len = off - output->coff; ++ len = off - output->dma->coff; + len -= (len % 188); + if (len <= 188) + +@@ -471,68 +578,146 @@ + } + if (len > left) + len = left; +- if (copy_from_user(output->vbuf[output->cbuf] + output->coff, ++ if (copy_from_user(output->dma->vbuf[output->dma->cbuf] + ++ output->dma->coff, + buf, len)) + return -EIO; ++ /* printk("cfu %d %d %d\n", len, output->cbuf, output->coff); */ + left -= len; + buf += len; +- output->coff += len; +- if (output->coff == output->dma_buf_size) { +- output->coff = 0; +- output->cbuf = ((output->cbuf + 1) % output->dma_buf_num); ++ output->dma->coff += len; ++ if (output->dma->coff == output->dma->size) { ++ output->dma->coff = 0; ++ output->dma->cbuf = ((output->dma->cbuf + 1) % ++ output->dma->num); + } +- ddbwritel((output->cbuf << 11) | (output->coff >> 7), +- DMA_BUFFER_ACK(output->nr + 8)); ++ ddbwritel(dev, (output->dma->cbuf << 11) | (output->dma->coff >> 7), ++ DMA_BUFFER_ACK(output->dma->nr)); + } + return count - left; + } + ++#if 0 ++static u32 ddb_input_free_bytes(struct ddb_input *input) ++{ ++ struct ddb *dev = input->port->dev; ++ u32 idx, off, stat = input->dma->stat; ++ u32 ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(input->dma->nr)); ++ ++ idx = (stat >> 11) & 0x1f; ++ off = (stat & 0x7ff) << 7; ++ ++ if (ctrl & 4) ++ return 0; ++ if (input->dma->cbuf != idx) ++ return 1; ++ return 0; ++} ++ ++static s32 ddb_output_used_bufs(struct ddb_output *output) ++{ ++ u32 idx, off, stat, ctrl; ++ s32 diff; ++ ++ spin_lock_irq(&output->dma->lock); ++ stat = output->dma->stat; ++ ctrl = output->dma->ctrl; ++ spin_unlock_irq(&output->dma->lock); ++ ++ idx = (stat >> 11) & 0x1f; ++ off = (stat & 0x7ff) << 7; ++ ++ if (ctrl & 4) ++ return 0; ++ diff = output->dma->cbuf - idx; ++ if (diff == 0 && off < output->dma->coff) ++ return 0; ++ if (diff <= 0) ++ diff += output->dma->num; ++ return diff; ++} ++ ++static s32 ddb_input_free_bufs(struct ddb_input *input) ++{ ++ u32 idx, off, stat, ctrl; ++ s32 free; ++ ++ spin_lock_irq(&input->dma->lock); ++ ctrl = input->dma->ctrl; ++ stat = input->dma->stat; ++ spin_unlock_irq(&input->dma->lock); ++ if (ctrl & 4) ++ return 0; ++ idx = (stat >> 11) & 0x1f; ++ off = (stat & 0x7ff) << 7; ++ free = input->dma->cbuf - idx; ++ if (free == 0 && off < input->dma->coff) ++ return 0; ++ if (free <= 0) ++ free += input->dma->num; ++ return free - 1; ++} ++ ++static u32 ddb_output_ok(struct ddb_output *output) ++{ ++ struct ddb_input *input = output->port->input[0]; ++ s32 diff; ++ ++ diff = ddb_input_free_bufs(input) - ddb_output_used_bufs(output); ++ if (diff > 0) ++ return 1; ++ return 0; ++} ++#endif ++ + static u32 ddb_input_avail(struct ddb_input *input) + { + struct ddb *dev = input->port->dev; +- u32 idx, off, stat = input->stat; +- u32 ctrl = ddbreadl(DMA_BUFFER_CONTROL(input->nr)); ++ u32 idx, off, stat = input->dma->stat; ++ u32 ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(input->dma->nr)); + + idx = (stat >> 11) & 0x1f; + off = (stat & 0x7ff) << 7; + + if (ctrl & 4) { + printk(KERN_ERR "IA %d %d %08x\n", idx, off, ctrl); +- ddbwritel(input->stat, DMA_BUFFER_ACK(input->nr)); ++ ddbwritel(dev, stat, DMA_BUFFER_ACK(input->dma->nr)); + return 0; + } +- if (input->cbuf != idx) ++ if (input->dma->cbuf != idx || off < input->dma->coff) + return 188; + return 0; + } + +-static ssize_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) ++static size_t ddb_input_read(struct ddb_input *input, u8 *buf, size_t count) + { + struct ddb *dev = input->port->dev; + u32 left = count; +- u32 idx, free, stat = input->stat; ++ u32 idx, off, free, stat = input->dma->stat; + int ret; + + idx = (stat >> 11) & 0x1f; ++ off = (stat & 0x7ff) << 7; + + while (left) { +- if (input->cbuf == idx) ++ if (input->dma->cbuf == idx) + return count - left; +- free = input->dma_buf_size - input->coff; ++ free = input->dma->size - input->dma->coff; + if (free > left) + free = left; +- ret = copy_to_user(buf, input->vbuf[input->cbuf] + +- input->coff, free); ++ ret = copy_to_user(buf, input->dma->vbuf[input->dma->cbuf] + ++ input->dma->coff, free); + if (ret) + return -EFAULT; +- input->coff += free; +- if (input->coff == input->dma_buf_size) { +- input->coff = 0; +- input->cbuf = (input->cbuf+1) % input->dma_buf_num; ++ input->dma->coff += free; ++ if (input->dma->coff == input->dma->size) { ++ input->dma->coff = 0; ++ input->dma->cbuf = (input->dma->cbuf+1) % ++ input->dma->num; + } + left -= free; +- ddbwritel((input->cbuf << 11) | (input->coff >> 7), +- DMA_BUFFER_ACK(input->nr)); ++ ddbwritel(dev, (input->dma->cbuf << 11) | (input->dma->coff >> 7), ++ DMA_BUFFER_ACK(input->dma->nr)); + } + return count; + } +@@ -554,7 +739,7 @@ + } + #endif + +-static int drxk_gate_ctrl(struct dvb_frontend *fe, int enable) ++static int locked_gate_ctrl(struct dvb_frontend *fe, int enable) + { + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; +@@ -562,9 +747,9 @@ + + if (enable) { + mutex_lock(&port->i2c_gate_lock); +- status = input->gate_ctrl(fe, 1); ++ status = input->dvb.gate_ctrl(fe, 1); + } else { +- status = input->gate_ctrl(fe, 0); ++ status = input->dvb.gate_ctrl(fe, 0); + mutex_unlock(&port->i2c_gate_lock); + } + return status; +@@ -577,18 +762,88 @@ + struct drxk_config config; + + memset(&config, 0, sizeof(config)); +- config.microcode_name = "drxk_a3.mc"; +- config.qam_demod_parameter_count = 4; + config.adr = 0x29 + (input->nr & 1); ++ config.microcode_name = "drxk_a3.mc"; + +- fe = input->fe = dvb_attach(drxk_attach, &config, i2c); +- if (!input->fe) { ++#ifdef USE_API3 ++ fe = input->dvb.fe = dvb_attach(drxk_attach, &config, i2c, &input->dvb.fe2); ++#else ++ fe = input->dvb.fe = dvb_attach(drxk_attach, &config, i2c); ++#endif ++ if (!input->dvb.fe) { + printk(KERN_ERR "No DRXK found!\n"); + return -ENODEV; + } + fe->sec_priv = input; +- input->gate_ctrl = fe->ops.i2c_gate_ctrl; +- fe->ops.i2c_gate_ctrl = drxk_gate_ctrl; ++ input->dvb.gate_ctrl = fe->ops.i2c_gate_ctrl; ++ fe->ops.i2c_gate_ctrl = locked_gate_ctrl; ++ return 0; ++} ++ ++#if 0 ++struct stv0367_config stv0367_0 = { ++ .demod_address = 0x1f, ++ .xtal = 27000000, ++ .if_khz = 5000, ++ .if_iq_mode = FE_TER_NORMAL_IF_TUNER, ++ .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, ++ .clk_pol = STV0367_RISINGEDGE_CLOCK, ++}; ++ ++struct stv0367_config stv0367_1 = { ++ .demod_address = 0x1e, ++ .xtal = 27000000, ++ .if_khz = 5000, ++ .if_iq_mode = FE_TER_NORMAL_IF_TUNER, ++ .ts_mode = STV0367_SERIAL_PUNCT_CLOCK, ++ .clk_pol = STV0367_RISINGEDGE_CLOCK, ++}; ++ ++ ++static int demod_attach_stv0367(struct ddb_input *input) ++{ ++ struct i2c_adapter *i2c = &input->port->i2c->adap; ++ struct dvb_frontend *fe; ++ ++ fe = input->dvb.fe = dvb_attach(stv0367ter_attach, ++ (input->nr & 1) ? &stv0367_1 : &stv0367_0, ++ i2c); ++ if (!input->dvb.fe) { ++ printk(KERN_ERR "No stv0367 found!\n"); ++ return -ENODEV; ++ } ++ fe->sec_priv = input; ++ input->dvb.gate_ctrl = fe->ops.i2c_gate_ctrl; ++ fe->ops.i2c_gate_ctrl = locked_gate_ctrl; ++ return 0; ++} ++#endif ++ ++struct stv0367_cfg stv0367dd_0 = { ++ .adr = 0x1f, ++ .xtal = 27000000, ++}; ++ ++struct stv0367_cfg stv0367dd_1 = { ++ .adr = 0x1e, ++ .xtal = 27000000, ++}; ++ ++static int demod_attach_stv0367dd(struct ddb_input *input) ++{ ++ struct i2c_adapter *i2c = &input->port->i2c->adap; ++ struct dvb_frontend *fe; ++ ++ fe = input->dvb.fe = dvb_attach(stv0367_attach, i2c, ++ (input->nr & 1) ? &stv0367dd_1 : &stv0367dd_0, ++ &input->dvb.fe2); ++ if (!input->dvb.fe) { ++ printk(KERN_ERR "No stv0367 found!\n"); ++ return -ENODEV; ++ } ++ fe->sec_priv = input; ++ input->dvb.gate_ctrl = fe->ops.i2c_gate_ctrl; ++ fe->ops.i2c_gate_ctrl = locked_gate_ctrl; + return 0; + } + +@@ -597,18 +852,57 @@ + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct dvb_frontend *fe; + +- if (input->fe->ops.i2c_gate_ctrl) +- input->fe->ops.i2c_gate_ctrl(input->fe, 1); +- fe = dvb_attach(tda18271c2dd_attach, input->fe, i2c, 0x60); ++ if (input->dvb.fe->ops.i2c_gate_ctrl) ++ input->dvb.fe->ops.i2c_gate_ctrl(input->dvb.fe, 1); ++ fe = dvb_attach(tda18271c2dd_attach, input->dvb.fe, i2c, 0x60); ++ if (input->dvb.fe->ops.i2c_gate_ctrl) ++ input->dvb.fe->ops.i2c_gate_ctrl(input->dvb.fe, 0); + if (!fe) { + printk(KERN_ERR "No TDA18271 found!\n"); + return -ENODEV; + } +- if (input->fe->ops.i2c_gate_ctrl) +- input->fe->ops.i2c_gate_ctrl(input->fe, 0); + return 0; + } + ++static int tuner_attach_tda18212dd(struct ddb_input *input) ++{ ++ struct i2c_adapter *i2c = &input->port->i2c->adap; ++ struct dvb_frontend *fe; ++ ++ fe = dvb_attach(tda18212dd_attach, input->dvb.fe, i2c, ++ (input->nr & 1) ? 0x63 : 0x60); ++ if (!fe) { ++ printk(KERN_ERR "No TDA18212 found!\n"); ++ return -ENODEV; ++ } ++ return 0; ++} ++ ++#if 0 ++struct tda18212_config tda18212_0 = { ++ .i2c_address = 0x60, ++}; ++ ++struct tda18212_config tda18212_1 = { ++ .i2c_address = 0x63, ++}; ++ ++static int tuner_attach_tda18212(struct ddb_input *input) ++{ ++ struct i2c_adapter *i2c = &input->port->i2c->adap; ++ struct dvb_frontend *fe; ++ struct tda18212_config *cfg; ++ ++ cfg = (input->nr & 1) ? &tda18212_1 : &tda18212_0; ++ fe = dvb_attach(tda18212_attach, input->dvb.fe, i2c, cfg); ++ if (!fe) { ++ printk(KERN_ERR "No TDA18212 found!\n"); ++ return -ENODEV; ++ } ++ return 0; ++} ++#endif ++ + /******************************************************************************/ + /******************************************************************************/ + /******************************************************************************/ +@@ -668,14 +962,14 @@ + struct i2c_adapter *i2c = &input->port->i2c->adap; + struct stv090x_config *feconf = type ? &stv0900_aa : &stv0900; + +- input->fe = dvb_attach(stv090x_attach, feconf, i2c, ++ input->dvb.fe = dvb_attach(stv090x_attach, feconf, i2c, + (input->nr & 1) ? STV090x_DEMODULATOR_1 + : STV090x_DEMODULATOR_0); +- if (!input->fe) { ++ if (!input->dvb.fe) { + printk(KERN_ERR "No STV0900 found!\n"); + return -ENODEV; + } +- if (!dvb_attach(lnbh24_attach, input->fe, i2c, 0, ++ if (!dvb_attach(lnbh24_attach, input->dvb.fe, i2c, 0, + 0, (input->nr & 1) ? + (0x09 - type) : (0x0b - type))) { + printk(KERN_ERR "No LNBH24 found!\n"); +@@ -692,7 +986,7 @@ + &stv6110b : &stv6110a; + struct stv6110x_devctl *ctl; + +- ctl = dvb_attach(stv6110x_attach, input->fe, tunerconf, i2c); ++ ctl = dvb_attach(stv6110x_attach, input->dvb.fe, tunerconf, i2c); + if (!ctl) { + printk(KERN_ERR "No STV6110X found!\n"); + return -ENODEV; +@@ -760,10 +1054,10 @@ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ddb_input *input = dvbdmx->priv; + +- if (!input->users) ++ if (!input->dvb.users) + ddb_input_start(input); + +- return ++input->users; ++ return ++input->dvb.users; + } + + static int stop_feed(struct dvb_demux_feed *dvbdmxfeed) +@@ -771,8 +1065,8 @@ + struct dvb_demux *dvbdmx = dvbdmxfeed->demux; + struct ddb_input *input = dvbdmx->priv; + +- if (--input->users) +- return input->users; ++ if (--input->dvb.users) ++ return input->dvb.users; + + ddb_input_stop(input); + return 0; +@@ -781,116 +1075,200 @@ + + static void dvb_input_detach(struct ddb_input *input) + { +- struct dvb_adapter *adap = &input->adap; +- struct dvb_demux *dvbdemux = &input->demux; ++ struct dvb_demux *dvbdemux = &input->dvb.demux; + +- switch (input->attached) { ++ switch (input->dvb.attached) { ++ case 6: ++ if (input->dvb.fe2) ++ dvb_unregister_frontend(input->dvb.fe2); ++ if (input->dvb.fe) ++ dvb_unregister_frontend(input->dvb.fe); + case 5: +- if (input->fe2) +- dvb_unregister_frontend(input->fe2); +- if (input->fe) { +- dvb_unregister_frontend(input->fe); +- dvb_frontend_detach(input->fe); +- input->fe = NULL; +- } ++ dvb_frontend_detach(input->dvb.fe); ++ input->dvb.fe = NULL; + case 4: +- dvb_net_release(&input->dvbnet); +- ++ dvb_net_release(&input->dvb.dvbnet); + case 3: + dvbdemux->dmx.close(&dvbdemux->dmx); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, +- &input->hw_frontend); ++ &input->dvb.hw_frontend); + dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, +- &input->mem_frontend); +- dvb_dmxdev_release(&input->dmxdev); +- ++ &input->dvb.mem_frontend); ++ dvb_dmxdev_release(&input->dvb.dmxdev); + case 2: +- dvb_dmx_release(&input->demux); +- ++ dvb_dmx_release(&input->dvb.demux); + case 1: +- dvb_unregister_adapter(adap); ++ break; ++ } ++ input->dvb.attached = 0; ++} ++ ++static int dvb_register_adapters(struct ddb *dev) ++{ ++ int i, ret = 0; ++ struct ddb_port *port; ++ struct dvb_adapter *adap; ++ ++ if (adapter_alloc == 3) { ++ port = &dev->port[0]; ++ adap = port->input[0]->dvb.adap; ++ ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, ++ &port->dev->pdev->dev, ++ adapter_nr); ++ if (ret < 0) ++ return ret; ++ port->input[0]->dvb.adap_registered = 1; ++ for (i = 0; i < dev->info->port_num; i++) { ++ port = &dev->port[i]; ++ port->input[0]->dvb.adap = adap; ++ port->input[1]->dvb.adap = adap; ++ } ++ return 0; ++ } ++ ++ for (i = 0; i < dev->info->port_num; i++) { ++ port = &dev->port[i]; ++ switch (port->class) { ++ case DDB_PORT_TUNER: ++ adap = port->input[0]->dvb.adap; ++ ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, ++ &port->dev->pdev->dev, ++ adapter_nr); ++ if (ret < 0) ++ return ret; ++ port->input[0]->dvb.adap_registered = 1; ++ ++ if (adapter_alloc > 0) { ++ port->input[1]->dvb.adap = port->input[0]->dvb.adap; ++ break; ++ } ++ adap = port->input[1]->dvb.adap; ++ ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, ++ &port->dev->pdev->dev, ++ adapter_nr); ++ if (ret < 0) ++ return ret; ++ port->input[1]->dvb.adap_registered = 1; ++ break; ++ ++ case DDB_PORT_CI: ++ case DDB_PORT_LOOP: ++ adap = port->input[0]->dvb.adap; ++ ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, ++ &port->dev->pdev->dev, ++ adapter_nr); ++ if (ret < 0) ++ return ret; ++ port->input[0]->dvb.adap_registered = 1; ++ break; ++ default: ++ if (adapter_alloc < 2) ++ break; ++ adap = port->input[0]->dvb.adap; ++ ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, ++ &port->dev->pdev->dev, ++ adapter_nr); ++ if (ret < 0) ++ return ret; ++ port->input[0]->dvb.adap_registered = 1; ++ break; ++ } ++ } ++ return ret; ++} ++ ++static void dvb_unregister_adapters(struct ddb *dev) ++{ ++ int i; ++ struct ddb_port *port; ++ struct ddb_input *input; ++ ++ for (i = 0; i < dev->info->port_num; i++) { ++ port = &dev->port[i]; ++ ++ input = port->input[0]; ++ if (input->dvb.adap_registered) ++ dvb_unregister_adapter(input->dvb.adap); ++ input->dvb.adap_registered = 0; ++ ++ input = port->input[1]; ++ if (input->dvb.adap_registered) ++ dvb_unregister_adapter(input->dvb.adap); ++ input->dvb.adap_registered = 0; + } +- input->attached = 0; + } + ++ + static int dvb_input_attach(struct ddb_input *input) + { +- int ret; ++ int ret = 0; + struct ddb_port *port = input->port; +- struct dvb_adapter *adap = &input->adap; +- struct dvb_demux *dvbdemux = &input->demux; ++ struct dvb_adapter *adap = input->dvb.adap; ++ struct dvb_demux *dvbdemux = &input->dvb.demux; + +- ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, +- &input->port->dev->pdev->dev, +- adapter_nr); +- if (ret < 0) { +- printk(KERN_ERR "ddbridge: Could not register adapter." +- "Check if you enabled enough adapters in dvb-core!\n"); +- return ret; +- } +- input->attached = 1; ++ input->dvb.attached = 1; + + ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux", + start_feed, + stop_feed, input); + if (ret < 0) + return ret; +- input->attached = 2; ++ input->dvb.attached = 2; + +- ret = my_dvb_dmxdev_ts_card_init(&input->dmxdev, &input->demux, +- &input->hw_frontend, +- &input->mem_frontend, adap); ++ ret = my_dvb_dmxdev_ts_card_init(&input->dvb.dmxdev, ++ &input->dvb.demux, ++ &input->dvb.hw_frontend, ++ &input->dvb.mem_frontend, adap); + if (ret < 0) + return ret; +- input->attached = 3; ++ input->dvb.attached = 3; + +- ret = dvb_net_init(adap, &input->dvbnet, input->dmxdev.demux); ++ ret = dvb_net_init(adap, &input->dvb.dvbnet, input->dvb.dmxdev.demux); + if (ret < 0) + return ret; +- input->attached = 4; ++ input->dvb.attached = 4; + +- input->fe = 0; ++ input->dvb.fe = 0; + switch (port->type) { + case DDB_TUNER_DVBS_ST: + if (demod_attach_stv0900(input, 0) < 0) + return -ENODEV; + if (tuner_attach_stv6110(input, 0) < 0) + return -ENODEV; +- if (input->fe) { +- if (dvb_register_frontend(adap, input->fe) < 0) +- return -ENODEV; +- } + break; + case DDB_TUNER_DVBS_ST_AA: + if (demod_attach_stv0900(input, 1) < 0) + return -ENODEV; + if (tuner_attach_stv6110(input, 1) < 0) + return -ENODEV; +- if (input->fe) { +- if (dvb_register_frontend(adap, input->fe) < 0) +- return -ENODEV; +- } + break; + case DDB_TUNER_DVBCT_TR: + if (demod_attach_drxk(input) < 0) + return -ENODEV; + if (tuner_attach_tda18271(input) < 0) + return -ENODEV; +- if (input->fe) { +- if (dvb_register_frontend(adap, input->fe) < 0) +- return -ENODEV; +- } +- if (input->fe2) { +- if (dvb_register_frontend(adap, input->fe2) < 0) +- return -ENODEV; +- input->fe2->tuner_priv = input->fe->tuner_priv; +- memcpy(&input->fe2->ops.tuner_ops, +- &input->fe->ops.tuner_ops, +- sizeof(struct dvb_tuner_ops)); +- } + break; ++ case DDB_TUNER_DVBCT_ST: ++ if (demod_attach_stv0367dd(input) < 0) ++ return -ENODEV; ++ if (tuner_attach_tda18212dd(input) < 0) ++ return -ENODEV; ++ break; ++ } ++ input->dvb.attached = 5; ++ if (input->dvb.fe) { ++ if (dvb_register_frontend(adap, input->dvb.fe) < 0) ++ return -ENODEV; ++ } ++ if (input->dvb.fe2) { ++ if (dvb_register_frontend(adap, input->dvb.fe2) < 0) ++ return -ENODEV; ++ input->dvb.fe2->tuner_priv = input->dvb.fe->tuner_priv; ++ memcpy(&input->dvb.fe2->ops.tuner_ops, ++ &input->dvb.fe->ops.tuner_ops, ++ sizeof(struct dvb_tuner_ops)); + } +- input->attached = 5; ++ input->dvb.attached = 6; + return 0; + } + +@@ -910,7 +1288,8 @@ + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible( +- output->wq, ddb_output_free(output) >= 188) < 0) ++ output->dma->wq, ++ ddb_output_free(output) >= 188) < 0) + break; + } + stat = ddb_output_write(output, buf, left); +@@ -937,7 +1316,7 @@ + if (file->f_flags & O_NONBLOCK) + break; + if (wait_event_interruptible( +- input->wq, ddb_input_avail(input) >= 188) < 0) ++ input->dma->wq, ddb_input_avail(input) >= 188) < 0) + break; + } + read = ddb_input_read(input, buf, left); +@@ -970,21 +1349,53 @@ + return mask; + } + +-static const struct file_operations ci_fops = { +- .owner = THIS_MODULE, +- .read = ts_read, +- .write = ts_write, +- .open = dvb_generic_open, +- .release = dvb_generic_release, +- .poll = ts_poll, +- .mmap = 0, +-}; +- +-static struct dvb_device dvbdev_ci = { ++#if 0 ++static int ts_release(struct inode *inode, struct file *file) ++{ ++ struct dvb_device *dvbdev = file->private_data; ++ struct ddb_output *output = dvbdev->priv; ++ struct ddb_input *input = output->port->input[0]; ++ ++ ++ return dvb_generic_release(inode, file); ++} ++ ++static unsigned int ts_open(struct inode *inode, struct file *file) ++{ ++ int err; ++ struct dvb_device *dvbdev = file->private_data; ++ struct ddb_output *output = dvbdev->priv; ++ struct ddb_input *input = output->port->input[0]; ++ ++ err = dvb_generic_open(inode, file); ++ if (err < 0) ++ return err; ++ ++#if 0 ++ if ((file->f_flags & O_ACCMODE) == O_RDONLY) ++ ddb_input_start(input); ++ else ++ ddb_output_start(output); ++#endif ++ return err; ++} ++#endif ++ ++static const struct file_operations ci_fops = { ++ .owner = THIS_MODULE, ++ .read = ts_read, ++ .write = ts_write, ++ .open = dvb_generic_open, ++ .release = dvb_generic_release, ++ .poll = ts_poll, ++ .mmap = 0, ++}; ++ ++static struct dvb_device dvbdev_ci = { + .priv = 0, +- .readers = -1, +- .writers = -1, +- .users = -1, ++ .readers = 1, ++ .writers = 1, ++ .users = 2, + .fops = &ci_fops, + }; + +@@ -992,53 +1403,297 @@ + /****************************************************************************/ + /****************************************************************************/ + ++static int set_redirect(u32 i, u32 p) ++{ ++ struct ddb *idev = ddbs[(i >> 4) & 0x1f]; ++ struct ddb_input *input; ++ struct ddb *pdev = ddbs[(p >> 4) & 0x1f]; ++ struct ddb_port *port; ++ ++ if (!idev || !pdev) ++ return -EINVAL; ++ ++ port = &pdev->port[p & 3]; ++ if (port->class != DDB_PORT_CI && port->class != DDB_PORT_LOOP) ++ return -EINVAL; ++ ++ ddb_unredirect(port); ++ if (i == 8) ++ return 0; ++ input = &idev->input[i & 7]; ++ if (input->port->class != DDB_PORT_TUNER) ++ port->input[0]->redirect = input->redirect; ++ else ++ port->input[0]->redirect = input; ++ input->redirect = port->input[0]; ++ port->output->redirect = input; ++ ++ ddb_redirect_dma(input->port->dev, input->dma, port->output->dma); ++ return 0; ++} ++ ++static void input_write_output(struct ddb_input *input, ++ struct ddb_output *output) ++{ ++ ddbwritel(output->port->dev, ++ input->dma->stat, DMA_BUFFER_ACK(output->dma->nr)); ++} ++ ++static void output_ack_input(struct ddb_output *output, ++ struct ddb_input *input) ++{ ++ ddbwritel(input->port->dev, ++ output->dma->stat, DMA_BUFFER_ACK(input->dma->nr)); ++} ++ ++static void input_write_dvb(struct ddb_input *input, struct ddb_dvb *dvb) ++{ ++ struct ddb_dma *dma = input->dma; ++ struct ddb *dev = input->port->dev; ++ ++ if (4 & ddbreadl(dev, DMA_BUFFER_CONTROL(dma->nr))) ++ printk(KERN_ERR "Overflow dma %d\n", dma->nr); ++ while (dma->cbuf != ((dma->stat >> 11) & 0x1f) ++ || (4 & ddbreadl(dev, DMA_BUFFER_CONTROL(dma->nr)))) { ++ dvb_dmx_swfilter_packets(&dvb->demux, ++ dma->vbuf[dma->cbuf], ++ dma->size / 188); ++ dma->cbuf = (dma->cbuf + 1) % dma->num; ++ ddbwritel(dev, (dma->cbuf << 11), DMA_BUFFER_ACK(dma->nr)); ++ dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma->nr)); ++ } ++} ++ + static void input_tasklet(unsigned long data) + { + struct ddb_input *input = (struct ddb_input *) data; ++ struct ddb_dma *dma = input->dma; + struct ddb *dev = input->port->dev; + +- spin_lock(&input->lock); +- if (!input->running) { +- spin_unlock(&input->lock); ++ spin_lock(&dma->lock); ++ if (!dma->running) { ++ spin_unlock(&dma->lock); + return; + } +- input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); ++ dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma->nr)); + + if (input->port->class == DDB_PORT_TUNER) { +- if (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr))) +- printk(KERN_ERR "Overflow input %d\n", input->nr); +- while (input->cbuf != ((input->stat >> 11) & 0x1f) +- || (4&ddbreadl(DMA_BUFFER_CONTROL(input->nr)))) { +- dvb_dmx_swfilter_packets(&input->demux, +- input->vbuf[input->cbuf], +- input->dma_buf_size / 188); +- +- input->cbuf = (input->cbuf + 1) % input->dma_buf_num; +- ddbwritel((input->cbuf << 11), +- DMA_BUFFER_ACK(input->nr)); +- input->stat = ddbreadl(DMA_BUFFER_CURRENT(input->nr)); +- } +- } +- if (input->port->class == DDB_PORT_CI) +- wake_up(&input->wq); +- spin_unlock(&input->lock); ++ if (input->redirect) ++ input_write_output(input, ++ input->redirect->port->output); ++ else ++ input_write_dvb(input, &input->dvb); ++ } ++ if (input->port->class == DDB_PORT_CI || ++ input->port->class == DDB_PORT_LOOP) { ++ if (input->redirect) { ++ if (input->redirect->port->class == DDB_PORT_TUNER) ++ input_write_dvb(input, &input->redirect->dvb); ++ else ++ input_write_output(input, ++ input->redirect->port->output); ++ } else ++ wake_up(&dma->wq); ++ } ++ spin_unlock(&dma->lock); + } + + static void output_tasklet(unsigned long data) + { + struct ddb_output *output = (struct ddb_output *) data; ++ struct ddb_dma *dma = output->dma; + struct ddb *dev = output->port->dev; + +- spin_lock(&output->lock); +- if (!output->running) { +- spin_unlock(&output->lock); ++ spin_lock(&dma->lock); ++ if (!dma->running) { ++ spin_unlock(&dma->lock); + return; + } +- output->stat = ddbreadl(DMA_BUFFER_CURRENT(output->nr + 8)); +- wake_up(&output->wq); +- spin_unlock(&output->lock); ++ dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma->nr)); ++ dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma->nr)); ++ if (output->redirect) ++ output_ack_input(output, output->redirect); ++ wake_up(&dma->wq); ++ spin_unlock(&dma->lock); ++} ++ ++#if 0 ++static void io_tasklet(unsigned long data) ++{ ++ struct ddb_dma *dma = (struct ddb_dma *) data; ++ ++ spin_lock(&dma->lock); ++ if (!dma->running) { ++ spin_unlock(&dma->lock); ++ return; ++ } ++ dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma->nr)); ++ dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma->nr)); ++ if (dma->nr & 8) ++ handle_output((struct ddb_output *) dma->io); ++ else ++ handle_input((struct ddb_input *) dma->io); ++ wake_up(&dma->wq); ++ spin_unlock(&dma->lock); ++} ++#endif ++ ++/****************************************************************************/ ++/****************************************************************************/ ++/****************************************************************************/ ++ ++static int wait_ci_ready(struct ddb_ci *ci) ++{ ++ u32 count = 100; ++ ++ do { ++ if (ddbreadl(ci->port->dev, ++ CI_CONTROL(ci->nr)) & CI_READY) ++ break; ++ msleep(1); ++ if ((--count) == 0) ++ return -1; ++ } while (1); ++ return 0; ++} ++ ++static int read_attribute_mem(struct dvb_ca_en50221 *ca, ++ int slot, int address) ++{ ++ struct ddb_ci *ci = ca->data; ++ u32 val, off = (address >> 1) & (CI_BUFFER_SIZE-1); ++ ++ if (address > CI_BUFFER_SIZE) ++ return -1; ++ ddbwritel(ci->port->dev, CI_READ_CMD | (1 << 16) | address, ++ CI_DO_READ_ATTRIBUTES(ci->nr)); ++ wait_ci_ready(ci); ++ val = 0xff & ddbreadl(ci->port->dev, CI_BUFFER(ci->nr) + off); ++ /* printk("%04x: %02x\n", address, val); */ ++ return val; ++} ++ ++static int write_attribute_mem(struct dvb_ca_en50221 *ca, int slot, ++ int address, u8 value) ++{ ++ struct ddb_ci *ci = ca->data; ++ ++ ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address, ++ CI_DO_ATTRIBUTE_RW(ci->nr)); ++ wait_ci_ready(ci); ++ return 0; ++} ++ ++static int read_cam_control(struct dvb_ca_en50221 *ca, ++ int slot, u8 address) ++{ ++ u32 count = 100; ++ struct ddb_ci *ci = ca->data; ++ u32 res; ++ ++ ddbwritel(ci->port->dev, CI_READ_CMD | address, ++ CI_DO_IO_RW(ci->nr)); ++ do { ++ res = ddbreadl(ci->port->dev, CI_READDATA(ci->nr)); ++ if (res & CI_READY) ++ break; ++ msleep(1); ++ if ((--count) == 0) ++ return -1; ++ } while (1); ++ return 0xff & res; ++} ++ ++static int write_cam_control(struct dvb_ca_en50221 *ca, int slot, ++ u8 address, u8 value) ++{ ++ struct ddb_ci *ci = ca->data; ++ ++ ddbwritel(ci->port->dev, CI_WRITE_CMD | (value << 16) | address, ++ CI_DO_IO_RW(ci->nr)); ++ wait_ci_ready(ci); ++ return 0; ++} ++ ++static int slot_reset(struct dvb_ca_en50221 *ca, int slot) ++{ ++ struct ddb_ci *ci = ca->data; ++ ++ printk(KERN_INFO "slot reset %d\n", ci->nr); ++ ddbwritel(ci->port->dev, CI_POWER_ON, ++ CI_CONTROL(ci->nr)); ++ msleep(300); ++ ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM, ++ CI_CONTROL(ci->nr)); ++ ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM, ++ CI_CONTROL(ci->nr)); ++ udelay(20); ++ ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON, ++ CI_CONTROL(ci->nr)); ++ return 0; ++} ++ ++static int slot_shutdown(struct dvb_ca_en50221 *ca, int slot) ++{ ++ struct ddb_ci *ci = ca->data; ++ ++ printk(KERN_INFO "slot shutdown\n"); ++ ddbwritel(ci->port->dev, 0, CI_CONTROL(ci->nr)); ++ return 0; ++} ++ ++static int slot_ts_enable(struct dvb_ca_en50221 *ca, int slot) ++{ ++ struct ddb_ci *ci = ca->data; ++ u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr)); ++ ++ ddbwritel(ci->port->dev, val | CI_BYPASS_DISABLE, ++ CI_CONTROL(ci->nr)); ++ return 0; ++} ++ ++static int poll_slot_status(struct dvb_ca_en50221 *ca, int slot, int open) ++{ ++ struct ddb_ci *ci = ca->data; ++ u32 val = ddbreadl(ci->port->dev, CI_CONTROL(ci->nr)); ++ int stat = 0; ++ ++ if (val & CI_CAM_DETECT) ++ stat |= DVB_CA_EN50221_POLL_CAM_PRESENT; ++ if (val & CI_CAM_READY) ++ stat |= DVB_CA_EN50221_POLL_CAM_READY; ++ return stat; + } + ++static struct dvb_ca_en50221 en_templ = { ++ .read_attribute_mem = read_attribute_mem, ++ .write_attribute_mem = write_attribute_mem, ++ .read_cam_control = read_cam_control, ++ .write_cam_control = write_cam_control, ++ .slot_reset = slot_reset, ++ .slot_shutdown = slot_shutdown, ++ .slot_ts_enable = slot_ts_enable, ++ .poll_slot_status = poll_slot_status, ++}; ++ ++static void ci_attach(struct ddb_port *port) ++{ ++ struct ddb_ci *ci = 0; ++ ++ ci = kzalloc(sizeof(*ci), GFP_KERNEL); ++ if (!ci) ++ return; ++ memcpy(&ci->en, &en_templ, sizeof(en_templ)); ++ ci->en.data = ci; ++ port->en = &ci->en; ++ ci->port = port; ++ ci->nr = port->nr - 2; ++} ++ ++/****************************************************************************/ ++/****************************************************************************/ ++/****************************************************************************/ ++ + + struct cxd2099_cfg cxd_cfg = { + .bitrate = 62000, +@@ -1049,28 +1704,22 @@ + + static int ddb_ci_attach(struct ddb_port *port) + { +- int ret; +- +- ret = dvb_register_adapter(&port->output->adap, +- "DDBridge", +- THIS_MODULE, +- &port->dev->pdev->dev, +- adapter_nr); +- if (ret < 0) +- return ret; +- port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); +- if (!port->en) { +- dvb_unregister_adapter(&port->output->adap); +- return -ENODEV; ++ if (port->type == DDB_CI_EXTERNAL_SONY) { ++ port->en = cxd2099_attach(&cxd_cfg, port, &port->i2c->adap); ++ if (!port->en) ++ return -ENODEV; ++ dvb_ca_en50221_init(port->input[0]->dvb.adap, ++ port->en, 0, 1); + } +- ddb_input_start(port->input[0]); +- ddb_output_start(port->output); +- dvb_ca_en50221_init(&port->output->adap, +- port->en, 0, 1); +- ret = dvb_register_device(&port->output->adap, &port->output->dev, +- &dvbdev_ci, (void *) port->output, +- DVB_DEVICE_SEC); +- return ret; ++#if 1 ++ if (port->type == DDB_CI_INTERNAL) { ++ ci_attach(port); ++ if (!port->en) ++ return -ENODEV; ++ dvb_ca_en50221_init(port->input[0]->dvb.adap, port->en, 0, 1); ++ } ++#endif ++ return 0; + } + + static int ddb_port_attach(struct ddb_port *port) +@@ -1086,6 +1735,15 @@ + break; + case DDB_PORT_CI: + ret = ddb_ci_attach(port); ++ if (ret < 0) ++ break; ++ case DDB_PORT_LOOP: ++ ddb_input_start(port->input[0]); ++ ddb_output_start(port->output); ++ ret = dvb_register_device(port->input[0]->dvb.adap, ++ &port->input[0]->dvb.dev, ++ &dvbdev_ci, (void *) port->output, ++ DVB_DEVICE_SEC); + break; + default: + break; +@@ -1100,6 +1758,10 @@ + int i, ret = 0; + struct ddb_port *port; + ++ ret = dvb_register_adapters(dev); ++ if (ret < 0) ++ return ret; ++ + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + ret = ddb_port_attach(port); +@@ -1122,25 +1784,26 @@ + dvb_input_detach(port->input[1]); + break; + case DDB_PORT_CI: +- if (port->output->dev) +- dvb_unregister_device(port->output->dev); ++ case DDB_PORT_LOOP: ++ if (port->input[0]->dvb.dev) ++ dvb_unregister_device(port->input[0]->dvb.dev); ++ ddb_input_stop(port->input[0]); ++ ddb_output_stop(port->output); + if (port->en) { +- ddb_input_stop(port->input[0]); +- ddb_output_stop(port->output); + dvb_ca_en50221_release(port->en); + kfree(port->en); + port->en = 0; +- dvb_unregister_adapter(&port->output->adap); + } + break; + } + } ++ dvb_unregister_adapters(dev); + } + + /****************************************************************************/ + /****************************************************************************/ + +-static int port_has_ci(struct ddb_port *port) ++static int port_has_cxd(struct ddb_port *port) + { + u8 val; + return i2c_read_reg(&port->i2c->adap, 0x40, 0, &val) ? 0 : 1; +@@ -1172,6 +1835,21 @@ + return 1; + } + ++static int port_has_stv0367(struct ddb_port *port) ++{ ++ u8 val; ++ ++ if (i2c_read_reg16(&port->i2c->adap, 0x1e, 0xf000, &val) < 0) ++ return 0; ++ if (val != 0x60) ++ return 0; ++ if (i2c_read_reg16(&port->i2c->adap, 0x1f, 0xf000, &val) < 0) ++ return 0; ++ if (val != 0x60) ++ return 0; ++ return 1; ++} ++ + static void ddb_port_probe(struct ddb_port *port) + { + struct ddb *dev = port->dev; +@@ -1179,62 +1857,92 @@ + + port->class = DDB_PORT_NONE; + +- if (port_has_ci(port)) { ++ if (port->nr > 1 && dev->info->type == DDB_OCTOPUS_CI) { ++ modname = "CI internal"; ++ port->class = DDB_PORT_CI; ++ port->type = DDB_CI_INTERNAL; ++ } else if (port_has_cxd(port)) { + modname = "CI"; + port->class = DDB_PORT_CI; +- ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); ++ port->type = DDB_CI_EXTERNAL_SONY; ++ ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0900(port)) { + modname = "DUAL DVB-S2"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBS_ST; +- ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); ++ ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_stv0900_aa(port)) { + modname = "DUAL DVB-S2"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBS_ST_AA; +- ddbwritel(I2C_SPEED_100, port->i2c->regs + I2C_TIMING); ++ ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); + } else if (port_has_drxks(port)) { + modname = "DUAL DVB-C/T"; + port->class = DDB_PORT_TUNER; + port->type = DDB_TUNER_DVBCT_TR; +- ddbwritel(I2C_SPEED_400, port->i2c->regs + I2C_TIMING); ++ ddbwritel(dev, I2C_SPEED_400, port->i2c->regs + I2C_TIMING); ++ } else if (port_has_stv0367(port)) { ++ modname = "DUAL DVB-C/T"; ++ port->class = DDB_PORT_TUNER; ++ port->type = DDB_TUNER_DVBCT_ST; ++ ddbwritel(dev, I2C_SPEED_100, port->i2c->regs + I2C_TIMING); ++ } else if (port->nr == ts_loop) { ++ modname = "TS LOOP"; ++ port->class = DDB_PORT_LOOP; ++ } ++ printk(KERN_INFO "Port %d (TAB %d): %s\n", port->nr, port->nr+1, modname); ++} ++ ++static void ddb_dma_init(struct ddb_dma *dma, int nr, void *io) ++{ ++ unsigned long priv = (unsigned long) io; ++ ++ dma->io = io; ++ dma->nr = nr; ++ spin_lock_init(&dma->lock); ++ init_waitqueue_head(&dma->wq); ++ if (nr & 8) { ++ tasklet_init(&dma->tasklet, output_tasklet, priv); ++ dma->num = OUTPUT_DMA_BUFS; ++ dma->size = OUTPUT_DMA_SIZE; ++ dma->div = OUTPUT_DMA_IRQ_DIV; ++ } else { ++ tasklet_init(&dma->tasklet, input_tasklet, priv); ++ dma->num = INPUT_DMA_BUFS; ++ dma->size = INPUT_DMA_SIZE; ++ dma->div = INPUT_DMA_IRQ_DIV; + } +- printk(KERN_INFO "Port %d (TAB %d): %s\n", +- port->nr, port->nr+1, modname); + } + +-static void ddb_input_init(struct ddb_port *port, int nr) ++static void ddb_input_init(struct ddb_port *port, int nr, int pnr) + { + struct ddb *dev = port->dev; + struct ddb_input *input = &dev->input[nr]; + ++ port->input[pnr] = input; + input->nr = nr; + input->port = port; +- input->dma_buf_num = INPUT_DMA_BUFS; +- input->dma_buf_size = INPUT_DMA_SIZE; +- ddbwritel(0, TS_INPUT_CONTROL(nr)); +- ddbwritel(2, TS_INPUT_CONTROL(nr)); +- ddbwritel(0, TS_INPUT_CONTROL(nr)); +- ddbwritel(0, DMA_BUFFER_ACK(nr)); +- tasklet_init(&input->tasklet, input_tasklet, (unsigned long) input); +- spin_lock_init(&input->lock); +- init_waitqueue_head(&input->wq); ++ input->dma = &dev->dma[nr]; ++ ddb_dma_init(input->dma, nr, (void *) input); ++ ddbwritel(dev, 0, TS_INPUT_CONTROL(nr)); ++ ddbwritel(dev, 2, TS_INPUT_CONTROL(nr)); ++ ddbwritel(dev, 0, TS_INPUT_CONTROL(nr)); ++ ddbwritel(dev, 0, DMA_BUFFER_ACK(input->dma->nr)); ++ input->dvb.adap = &dev->adap[input->nr]; + } + + static void ddb_output_init(struct ddb_port *port, int nr) + { + struct ddb *dev = port->dev; + struct ddb_output *output = &dev->output[nr]; ++ port->output = output; + output->nr = nr; + output->port = port; +- output->dma_buf_num = OUTPUT_DMA_BUFS; +- output->dma_buf_size = OUTPUT_DMA_SIZE; +- +- ddbwritel(0, TS_OUTPUT_CONTROL(nr)); +- ddbwritel(2, TS_OUTPUT_CONTROL(nr)); +- ddbwritel(0, TS_OUTPUT_CONTROL(nr)); +- tasklet_init(&output->tasklet, output_tasklet, (unsigned long) output); +- init_waitqueue_head(&output->wq); ++ output->dma = &dev->dma[nr + 8]; ++ ddb_dma_init(output->dma, nr + 8, (void *) output); ++ ddbwritel(dev, 0, TS_OUTPUT_CONTROL(nr)); ++ ddbwritel(dev, 2, TS_OUTPUT_CONTROL(nr)); ++ ddbwritel(dev, 0, TS_OUTPUT_CONTROL(nr)); + } + + static void ddb_ports_init(struct ddb *dev) +@@ -1247,14 +1955,16 @@ + port->dev = dev; + port->nr = i; + port->i2c = &dev->i2c[i]; +- port->input[0] = &dev->input[2 * i]; +- port->input[1] = &dev->input[2 * i + 1]; +- port->output = &dev->output[i]; + + mutex_init(&port->i2c_gate_lock); + ddb_port_probe(port); +- ddb_input_init(port, 2 * i); +- ddb_input_init(port, 2 * i + 1); ++ if (i >= 2 && dev->info->type == DDB_OCTOPUS_CI) { ++ ddb_input_init(port, 2 + i, 0); ++ ddb_input_init(port, 4 + i, 1); ++ } else { ++ ddb_input_init(port, 2 * i, 0); ++ ddb_input_init(port, 2 * i + 1, 1); ++ } + ddb_output_init(port, i); + } + } +@@ -1267,9 +1977,12 @@ + for (i = 0; i < dev->info->port_num; i++) { + port = &dev->port[i]; + port->dev = dev; +- tasklet_kill(&port->input[0]->tasklet); +- tasklet_kill(&port->input[1]->tasklet); +- tasklet_kill(&port->output->tasklet); ++ if (port->input[0]) ++ tasklet_kill(&port->input[0]->dma->tasklet); ++ if (port->input[1]) ++ tasklet_kill(&port->input[1]->dma->tasklet); ++ if (port->output) ++ tasklet_kill(&port->output->dma->tasklet); + } + } + +@@ -1288,13 +2001,18 @@ + static irqreturn_t irq_handler(int irq, void *dev_id) + { + struct ddb *dev = (struct ddb *) dev_id; +- u32 s = ddbreadl(INTERRUPT_STATUS); ++ u32 s = ddbreadl(dev, INTERRUPT_STATUS); + + if (!s) + return IRQ_NONE; + + do { +- ddbwritel(s, INTERRUPT_ACK); ++ ddbwritel(dev, s, INTERRUPT_ACK); ++ ++ if (s & 0x0000000f) ++ dev->i2c_irq++; ++ if (s & 0x000fff00) ++ dev->ts_irq++; + + if (s & 0x00000001) + irq_handle_i2c(dev, 0); +@@ -1306,33 +2024,32 @@ + irq_handle_i2c(dev, 3); + + if (s & 0x00000100) +- tasklet_schedule(&dev->input[0].tasklet); ++ tasklet_schedule(&dev->dma[0].tasklet); + if (s & 0x00000200) +- tasklet_schedule(&dev->input[1].tasklet); ++ tasklet_schedule(&dev->dma[1].tasklet); + if (s & 0x00000400) +- tasklet_schedule(&dev->input[2].tasklet); ++ tasklet_schedule(&dev->dma[2].tasklet); + if (s & 0x00000800) +- tasklet_schedule(&dev->input[3].tasklet); ++ tasklet_schedule(&dev->dma[3].tasklet); + if (s & 0x00001000) +- tasklet_schedule(&dev->input[4].tasklet); ++ tasklet_schedule(&dev->dma[4].tasklet); + if (s & 0x00002000) +- tasklet_schedule(&dev->input[5].tasklet); ++ tasklet_schedule(&dev->dma[5].tasklet); + if (s & 0x00004000) +- tasklet_schedule(&dev->input[6].tasklet); ++ tasklet_schedule(&dev->dma[6].tasklet); + if (s & 0x00008000) +- tasklet_schedule(&dev->input[7].tasklet); +- ++ tasklet_schedule(&dev->dma[7].tasklet); + if (s & 0x00010000) +- tasklet_schedule(&dev->output[0].tasklet); ++ tasklet_schedule(&dev->dma[8].tasklet); + if (s & 0x00020000) +- tasklet_schedule(&dev->output[1].tasklet); ++ tasklet_schedule(&dev->dma[9].tasklet); + if (s & 0x00040000) +- tasklet_schedule(&dev->output[2].tasklet); ++ tasklet_schedule(&dev->dma[10].tasklet); + if (s & 0x00080000) +- tasklet_schedule(&dev->output[3].tasklet); ++ tasklet_schedule(&dev->dma[11].tasklet); + +- /* if (s & 0x000f0000) printk(KERN_DEBUG "%08x\n", istat); */ +- } while ((s = ddbreadl(INTERRUPT_STATUS))); ++ /* if (s & 0x000f0000) printk("%08x\n", istat); */ ++ } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); + + return IRQ_HANDLED; + } +@@ -1346,21 +2063,21 @@ + u32 data, shift; + + if (wlen > 4) +- ddbwritel(1, SPI_CONTROL); ++ ddbwritel(dev, 1, SPI_CONTROL); + while (wlen > 4) { + /* FIXME: check for big-endian */ + data = swab32(*(u32 *)wbuf); + wbuf += 4; + wlen -= 4; +- ddbwritel(data, SPI_DATA); +- while (ddbreadl(SPI_CONTROL) & 0x0004) ++ ddbwritel(dev, data, SPI_DATA); ++ while (ddbreadl(dev, SPI_CONTROL) & 0x0004) + ; + } + + if (rlen) +- ddbwritel(0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); ++ ddbwritel(dev, 0x0001 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); + else +- ddbwritel(0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); ++ ddbwritel(dev, 0x0003 | ((wlen << (8 + 3)) & 0x1f00), SPI_CONTROL); + + data = 0; + shift = ((4 - wlen) * 8); +@@ -1372,33 +2089,33 @@ + } + if (shift) + data <<= shift; +- ddbwritel(data, SPI_DATA); +- while (ddbreadl(SPI_CONTROL) & 0x0004) ++ ddbwritel(dev, data, SPI_DATA); ++ while (ddbreadl(dev, SPI_CONTROL) & 0x0004) + ; + + if (!rlen) { +- ddbwritel(0, SPI_CONTROL); ++ ddbwritel(dev, 0, SPI_CONTROL); + return 0; + } + if (rlen > 4) +- ddbwritel(1, SPI_CONTROL); ++ ddbwritel(dev, 1, SPI_CONTROL); + + while (rlen > 4) { +- ddbwritel(0xffffffff, SPI_DATA); +- while (ddbreadl(SPI_CONTROL) & 0x0004) ++ ddbwritel(dev, 0xffffffff, SPI_DATA); ++ while (ddbreadl(dev, SPI_CONTROL) & 0x0004) + ; +- data = ddbreadl(SPI_DATA); ++ data = ddbreadl(dev, SPI_DATA); + *(u32 *) rbuf = swab32(data); + rbuf += 4; + rlen -= 4; + } +- ddbwritel(0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL); +- ddbwritel(0xffffffff, SPI_DATA); +- while (ddbreadl(SPI_CONTROL) & 0x0004) ++ ddbwritel(dev, 0x0003 | ((rlen << (8 + 3)) & 0x1F00), SPI_CONTROL); ++ ddbwritel(dev, 0xffffffff, SPI_DATA); ++ while (ddbreadl(dev, SPI_CONTROL) & 0x0004) + ; + +- data = ddbreadl(SPI_DATA); +- ddbwritel(0, SPI_CONTROL); ++ data = ddbreadl(dev, SPI_DATA); ++ ddbwritel(dev, 0, SPI_CONTROL); + + if (rlen < 4) + data <<= ((4 - rlen) * 8); +@@ -1421,14 +2138,21 @@ + __u32 read_len; + }; + ++struct ddb_gpio { ++ __u32 mask; ++ __u32 data; ++}; ++ ++ + #define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio) ++#define IOCTL_DDB_GPIO_IN _IOWR(DDB_MAGIC, 0x01, struct ddb_gpio) ++#define IOCTL_DDB_GPIO_OUT _IOWR(DDB_MAGIC, 0x02, struct ddb_gpio) + + #define DDB_NAME "ddbridge" + + static u32 ddb_num; +-static struct ddb *ddbs[32]; +-static struct class *ddb_class; + static int ddb_major; ++static DEFINE_MUTEX(ddb_mutex); + + static int ddb_open(struct inode *inode, struct file *file) + { +@@ -1470,6 +2194,16 @@ + return -EFAULT; + break; + } ++ case IOCTL_DDB_GPIO_OUT: ++ { ++ struct ddb_gpio gpio; ++ if (copy_from_user(&gpio, parg, sizeof(gpio))) ++ break; ++ ddbwritel(dev, gpio.mask, GPIO_DIRECTION); ++ ddbwritel(dev, gpio.data, GPIO_OUTPUT); ++ res = 0; ++ break; ++ } + default: + return -ENOTTY; + } +@@ -1481,41 +2215,249 @@ + .open = ddb_open, + }; + +-static char *ddb_devnode(struct device *device, umode_t *mode) ++static char *ddb_devnode(struct device *device, mode_t *mode) + { + struct ddb *dev = dev_get_drvdata(device); + + return kasprintf(GFP_KERNEL, "ddbridge/card%d", dev->nr); + } + ++static ssize_t ports_show(struct device *device, struct device_attribute *attr, char *buf) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ ++ return sprintf(buf, "%d\n", dev->info->port_num); ++} ++ ++static ssize_t ts_irq_show(struct device *device, struct device_attribute *attr, char *buf) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ ++ return sprintf(buf, "%d\n", dev->ts_irq); ++} ++ ++static ssize_t i2c_irq_show(struct device *device, struct device_attribute *attr, char *buf) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ ++ return sprintf(buf, "%d\n", dev->i2c_irq); ++} ++ ++static char *class_name[] = { ++ "NONE", "CI", "TUNER", "LOOP" ++}; ++ ++static char *type_name[] = { ++ "NONE", "DVBS_ST", "DVBS_ST_AA", "DVBCT_TR", "DVBCT_ST", "INTERNAL", "CXD2099", ++}; ++ ++static ssize_t fan_show(struct device *device, struct device_attribute *attr, char *buf) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ u32 val; ++ ++ val = ddbreadl(dev, GPIO_OUTPUT) & 1; ++ return sprintf(buf, "%d\n", val); ++} ++ ++static ssize_t fan_store(struct device *device, struct device_attribute *d, ++ const char *buf, size_t count) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ unsigned val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ ddbwritel(dev, 1, GPIO_DIRECTION); ++ ddbwritel(dev, val & 1, GPIO_OUTPUT); ++ return count; ++} ++ ++static ssize_t temp_show(struct device *device, struct device_attribute *attr, char *buf) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ int temp; ++ u8 tmp[2]; ++ ++ if (!dev->info->temp_num) ++ return sprintf(buf, "no sensor\n"); ++ if (i2c_read_regs(&dev->i2c[0].adap, 0x48, 0, tmp, 2) < 0) ++ return sprintf(buf, "read_error\n"); ++ temp = (tmp[0] << 3) | (tmp[1] >> 5); ++ temp *= 125; ++ return sprintf(buf, "%d\n", temp); ++} ++ ++static ssize_t mod_show(struct device *device, struct device_attribute *attr, char *buf) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ int num = attr->attr.name[3] - 0x30; ++ ++ return sprintf(buf, "%s:%s\n", ++ class_name[dev->port[num].class], ++ type_name[dev->port[num].type]); ++} ++ ++static ssize_t led_show(struct device *device, struct device_attribute *attr, char *buf) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ int num = attr->attr.name[3] - 0x30; ++ ++ return sprintf(buf, "%d\n", dev->leds & (1 << num) ? 1 : 0); ++} ++ ++ ++static void ddb_set_led(struct ddb *dev, int num, int val) ++{ ++ if (!dev->info->led_num) ++ return; ++ switch (dev->port[num].class) { ++ case DDB_PORT_TUNER: ++ switch (dev->port[num].type) { ++ case DDB_TUNER_DVBS_ST: ++ printk(KERN_INFO "LED %d %d\n", num, val); ++ i2c_write_reg16(&dev->i2c[num].adap, ++ 0x69, 0xf14c, val ? 2 : 0); ++ break; ++ case DDB_TUNER_DVBCT_ST: ++ printk(KERN_INFO "LED %d %d\n", num, val); ++ i2c_write_reg16(&dev->i2c[num].adap, ++ 0x1f, 0xf00e, 0); ++ i2c_write_reg16(&dev->i2c[num].adap, ++ 0x1f, 0xf00f, val ? 1 : 0); ++ break; ++ } ++ break; ++ default: ++ break; ++ } ++} ++ ++static ssize_t led_store(struct device *device, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ int num = attr->attr.name[3] - 0x30; ++ unsigned val; ++ ++ if (sscanf(buf, "%u\n", &val) != 1) ++ return -EINVAL; ++ if (val) ++ dev->leds |= (1 << num); ++ else ++ dev->leds &= ~(1 << num); ++ ddb_set_led(dev, num, val); ++ return count; ++} ++ ++static ssize_t snr_show(struct device *device, struct device_attribute *attr, char *buf) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ char snr[32]; ++ int num = attr->attr.name[3] - 0x30; ++ ++ /* serial number at 0x100-0x11f */ ++ if (i2c_read_regs16(&dev->i2c[num].adap, 0x57, 0x100, snr, 32) < 0) ++ return sprintf(buf, "NO SNR\n"); ++ snr[31] = 0; /* in case it is not terminated on EEPROM */ ++ return sprintf(buf, "%s\n", snr); ++} ++ ++ ++static ssize_t snr_store(struct device *device, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ struct ddb *dev = dev_get_drvdata(device); ++ int num = attr->attr.name[3] - 0x30; ++ u8 snr[34] = { 0x01, 0x00 }; ++ ++ if (count > 31) ++ return -EINVAL; ++ memcpy(snr + 2, buf, count); ++ i2c_write(&dev->i2c[num].adap, 0x57, snr, 34); ++ return count; ++} ++ ++static ssize_t redirect_show(struct device *device, struct device_attribute *attr, char *buf) ++{ ++ return 0; ++} ++ ++static ssize_t redirect_store(struct device *device, struct device_attribute *attr, ++ const char *buf, size_t count) ++{ ++ unsigned int i, p; ++ int res; ++ ++ if (sscanf(buf, "%x %x\n", &i, &p) != 2) ++ return -EINVAL; ++ printk(KERN_INFO "redirect: %02x, %02x\n", i, p); ++ res = set_redirect(i, p); ++ if (res < 0) ++ return res; ++ return count; ++} ++ ++#define __ATTR_MRO(_name, _show) { \ ++ .attr = { .name = __stringify(_name), .mode = 0444 }, \ ++ .show = _show, \ ++} ++ ++struct device_attribute ddb_attrs[] = { ++ __ATTR_RO(ports), ++ __ATTR_RO(ts_irq), ++ __ATTR_RO(i2c_irq), ++ __ATTR_MRO(mod0, mod_show), ++ __ATTR_MRO(mod1, mod_show), ++ __ATTR_MRO(mod2, mod_show), ++ __ATTR_MRO(mod3, mod_show), ++ __ATTR_RO(temp), ++ __ATTR(fan, 0666, fan_show, fan_store), ++ __ATTR(led0, 0666, led_show, led_store), ++ __ATTR(led1, 0666, led_show, led_store), ++ __ATTR(led2, 0666, led_show, led_store), ++ __ATTR(led3, 0666, led_show, led_store), ++ __ATTR(snr0, 0666, snr_show, snr_store), ++ __ATTR(snr1, 0666, snr_show, snr_store), ++ __ATTR(snr2, 0666, snr_show, snr_store), ++ __ATTR(snr3, 0666, snr_show, snr_store), ++ __ATTR(redirect, 0666, redirect_show, redirect_store), ++ __ATTR_NULL ++}; ++ ++static struct class ddb_class = { ++ .name = "ddbridge", ++ .owner = THIS_MODULE, ++ .dev_attrs = ddb_attrs, ++ .devnode = ddb_devnode, ++}; ++ + static int ddb_class_create(void) + { + ddb_major = register_chrdev(0, DDB_NAME, &ddb_fops); + if (ddb_major < 0) + return ddb_major; + +- ddb_class = class_create(THIS_MODULE, DDB_NAME); +- if (IS_ERR(ddb_class)) { +- unregister_chrdev(ddb_major, DDB_NAME); +- return PTR_ERR(ddb_class); +- } +- ddb_class->devnode = ddb_devnode; ++ if (class_register(&ddb_class) < 0) ++ return -1; + return 0; + } + + static void ddb_class_destroy(void) + { +- class_destroy(ddb_class); ++ class_unregister(&ddb_class); + unregister_chrdev(ddb_major, DDB_NAME); + } + + static int ddb_device_create(struct ddb *dev) + { ++ mutex_lock(&ddb_mutex); + dev->nr = ddb_num++; +- dev->ddb_dev = device_create(ddb_class, NULL, ++ ddbs[dev->nr] = dev; ++ mutex_unlock(&ddb_mutex); ++ dev->ddb_dev = device_create(&ddb_class, &dev->pdev->dev, + MKDEV(ddb_major, dev->nr), + dev, "ddbridge%d", dev->nr); +- ddbs[dev->nr] = dev; + if (IS_ERR(dev->ddb_dev)) + return -1; + return 0; +@@ -1523,10 +2465,9 @@ + + static void ddb_device_destroy(struct ddb *dev) + { +- ddb_num--; + if (IS_ERR(dev->ddb_dev)) + return; +- device_destroy(ddb_class, MKDEV(ddb_major, 0)); ++ device_destroy(&ddb_class, MKDEV(ddb_major, dev->nr)); + } + + +@@ -1549,7 +2490,7 @@ + ddb_ports_detach(dev); + ddb_i2c_release(dev); + +- ddbwritel(0, INTERRUPT_ENABLE); ++ ddbwritel(dev, 0, INTERRUPT_ENABLE); + free_irq(dev->pdev->irq, dev); + #ifdef CONFIG_PCI_MSI + if (dev->msi) +@@ -1564,7 +2505,6 @@ + pci_disable_device(pdev); + } + +- + static int __devinit ddb_probe(struct pci_dev *pdev, + const struct pci_device_id *id) + { +@@ -1575,10 +2515,9 @@ + if (pci_enable_device(pdev) < 0) + return -ENODEV; + +- dev = vmalloc(sizeof(struct ddb)); ++ dev = vzalloc(sizeof(struct ddb)); + if (dev == NULL) + return -ENOMEM; +- memset(dev, 0, sizeof(struct ddb)); + + dev->pdev = pdev; + pci_set_drvdata(pdev, dev); +@@ -1591,7 +2530,8 @@ + stat = -ENOMEM; + goto fail; + } +- printk(KERN_INFO "HW %08x FW %08x\n", ddbreadl(0), ddbreadl(4)); ++ printk(KERN_INFO "HW %08x REG %08x\n", ++ ddbreadl(dev, 0), ddbreadl(dev, 4)); + + #ifdef CONFIG_PCI_MSI + if (pci_msi_enabled()) +@@ -1607,11 +2547,11 @@ + irq_flag, "DDBridge", (void *) dev); + if (stat < 0) + goto fail1; +- ddbwritel(0, DMA_BASE_WRITE); +- ddbwritel(0, DMA_BASE_READ); +- ddbwritel(0xffffffff, INTERRUPT_ACK); +- ddbwritel(0xfff0f, INTERRUPT_ENABLE); +- ddbwritel(0, MSI1_ENABLE); ++ ddbwritel(dev, 0, DMA_BASE_WRITE); ++ ddbwritel(dev, 0, DMA_BASE_READ); ++ ddbwritel(dev, 0xffffffff, INTERRUPT_ACK); ++ ddbwritel(dev, 0x000fff0f, INTERRUPT_ENABLE); ++ ddbwritel(dev, 0, MSI1_ENABLE); + + if (ddb_i2c_init(dev) < 0) + goto fail1; +@@ -1622,7 +2562,13 @@ + } + if (ddb_ports_attach(dev) < 0) + goto fail3; ++ + ddb_device_create(dev); ++ ++ if (dev->info->fan_num) { ++ ddbwritel(dev, 1, GPIO_DIRECTION); ++ ddbwritel(dev, 1, GPIO_OUTPUT); ++ } + return 0; + + fail3: +@@ -1632,11 +2578,14 @@ + fail2: + printk(KERN_ERR "fail2\n"); + ddb_buffers_free(dev); ++ ddb_i2c_release(dev); + fail1: + printk(KERN_ERR "fail1\n"); ++ free_irq(dev->pdev->irq, dev); ++#ifdef CONFIG_PCI_MSI + if (dev->msi) + pci_disable_msi(dev->pdev); +- free_irq(dev->pdev->irq, dev); ++#endif + fail: + printk(KERN_ERR "fail\n"); + ddb_unmap(dev); +@@ -1658,23 +2607,71 @@ + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus DVB adapter", + .port_num = 4, ++ .i2c_num = 4, + }; + + static struct ddb_info ddb_octopus_le = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Octopus LE DVB adapter", + .port_num = 2, ++ .i2c_num = 2, ++}; ++ ++static struct ddb_info ddb_octopus_oem = { ++ .type = DDB_OCTOPUS, ++ .name = "Digital Devices Octopus OEM", ++ .port_num = 4, ++ .i2c_num = 4, ++ .led_num = 1, ++ .fan_num = 1, ++ .temp_num = 1, ++}; ++ ++static struct ddb_info ddb_octopus_mini = { ++ .type = DDB_OCTOPUS, ++ .name = "Digital Devices Octopus Mini", ++ .port_num = 4, ++ .i2c_num = 4, + }; + + static struct ddb_info ddb_v6 = { + .type = DDB_OCTOPUS, + .name = "Digital Devices Cine S2 V6 DVB adapter", + .port_num = 3, ++ .i2c_num = 3, ++}; ++ ++static struct ddb_info ddb_dvbct = { ++ .type = DDB_OCTOPUS, ++ .name = "Digital Devices DVBCT V6.1 DVB adapter", ++ .port_num = 3, ++ .i2c_num = 3, ++}; ++ ++static struct ddb_info ddb_satixS2v3 = { ++ .type = DDB_OCTOPUS, ++ .name = "Mystique SaTiX-S2 V3 DVB adapter", ++ .port_num = 3, ++ .i2c_num = 3, ++}; ++ ++static struct ddb_info ddb_ci = { ++ .type = DDB_OCTOPUS_CI, ++ .name = "Digital Devices Octopus CI", ++ .port_num = 4, ++ .i2c_num = 2, ++}; ++ ++static struct ddb_info ddb_cis = { ++ .type = DDB_OCTOPUS_CI, ++ .name = "Digital Devices Octopus CI single", ++ .port_num = 3, ++ .i2c_num = 2, + }; + + #define DDVID 0xdd01 /* Digital Devices Vendor ID */ + +-#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \ ++#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \ + .vendor = _vend, .device = _dev, \ + .subvendor = _subvend, .subdevice = _subdev, \ + .driver_data = (unsigned long)&_driverdata } +@@ -1683,8 +2680,13 @@ + DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus), + DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus), + DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le), +- DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus), ++ DDB_ID(DDVID, 0x0003, DDVID, 0x0003, ddb_octopus_oem), ++ DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus_mini), + DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6), ++ DDB_ID(DDVID, 0x0003, DDVID, 0x0030, ddb_dvbct), ++ DDB_ID(DDVID, 0x0003, DDVID, 0xdb03, ddb_satixS2v3), ++ DDB_ID(DDVID, 0x0011, DDVID, 0x0040, ddb_ci), ++ DDB_ID(DDVID, 0x0011, DDVID, 0x0041, ddb_cis), + /* in case sub-ids got deleted in flash */ + DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none), + {0} +@@ -1696,7 +2698,7 @@ + .name = "DDBridge", + .id_table = ddb_id_tbl, + .probe = ddb_probe, +- .remove = __devexit_p(ddb_remove), ++ .remove = ddb_remove, + }; + + static __init int module_init_ddbridge(void) +@@ -1727,4 +2729,4 @@ + MODULE_DESCRIPTION("Digital Devices PCIe Bridge"); + MODULE_AUTHOR("Ralph Metzler"); + MODULE_LICENSE("GPL"); +-MODULE_VERSION("0.5"); ++MODULE_VERSION("0.8"); +diff -Naur linux-3.7.3/drivers/media/pci/ddbridge/ddbridge.h linux-3.7.3.patch/drivers/media/pci/ddbridge/ddbridge.h +--- linux-3.7.3/drivers/media/pci/ddbridge/ddbridge.h 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ddbridge/ddbridge.h 2013-01-20 01:02:21.440090976 +0100 +@@ -32,7 +32,10 @@ + #include + #include + #include ++#include ++#include + #include ++#include + + #include "dmxdev.h" + #include "dvbdev.h" +@@ -52,43 +55,53 @@ + int type; + #define DDB_NONE 0 + #define DDB_OCTOPUS 1 ++#define DDB_OCTOPUS_CI 2 + char *name; + int port_num; +- u32 port_type[DDB_MAX_PORT]; ++ int i2c_num; ++ int led_num; ++ int fan_num; ++ int temp_num; + }; + + /* DMA_SIZE MUST be divisible by 188 and 128 !!! */ + +-#define INPUT_DMA_MAX_BUFS 32 /* hardware table limit */ ++#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_MAX_BUFS 32 + #define OUTPUT_DMA_BUFS 8 + #define OUTPUT_DMA_SIZE (128*47*21) ++#define OUTPUT_DMA_IRQ_DIV 1 + + struct ddb; + struct ddb_port; + +-struct ddb_input { +- struct ddb_port *port; ++struct ddb_dma { ++ void *io; + u32 nr; +- int attached; +- +- dma_addr_t pbuf[INPUT_DMA_MAX_BUFS]; +- u8 *vbuf[INPUT_DMA_MAX_BUFS]; +- u32 dma_buf_num; +- u32 dma_buf_size; ++ dma_addr_t pbuf[DMA_MAX_BUFS]; ++ u8 *vbuf[DMA_MAX_BUFS]; ++ u32 num; ++ u32 size; ++ u32 div; ++ u32 bufreg; + + struct tasklet_struct tasklet; + spinlock_t lock; + wait_queue_head_t wq; + int running; + u32 stat; ++ u32 ctrl; + u32 cbuf; + u32 coff; ++}; + +- struct dvb_adapter adap; ++struct ddb_dvb { ++ struct dvb_adapter *adap; ++ int adap_registered; + struct dvb_device *dev; + struct dvb_frontend *fe; + struct dvb_frontend *fe2; +@@ -99,32 +112,36 @@ + struct dmx_frontend mem_frontend; + int users; + int (*gate_ctrl)(struct dvb_frontend *, int); ++ int attached; + }; + +-struct ddb_output { ++struct ddb_ci { ++ struct dvb_ca_en50221 en; + struct ddb_port *port; + u32 nr; +- dma_addr_t pbuf[OUTPUT_DMA_MAX_BUFS]; +- u8 *vbuf[OUTPUT_DMA_MAX_BUFS]; +- u32 dma_buf_num; +- u32 dma_buf_size; +- struct tasklet_struct tasklet; +- spinlock_t lock; +- wait_queue_head_t wq; +- int running; +- u32 stat; +- u32 cbuf; +- u32 coff; ++}; + +- struct dvb_adapter adap; +- struct dvb_device *dev; ++ ++struct ddb_input { ++ struct ddb_port *port; ++ u32 nr; ++ struct ddb_dma *dma; ++ struct ddb_input *redirect; ++ ++ struct ddb_dvb dvb; ++}; ++ ++struct ddb_output { ++ struct ddb_port *port; ++ u32 nr; ++ struct ddb_dma *dma; ++ struct ddb_input *redirect; + }; + + struct ddb_i2c { + struct ddb *dev; + u32 nr; + struct i2c_adapter adap; +- struct i2c_adapter adap2; + u32 regs; + u32 rbuf; + u32 wbuf; +@@ -141,12 +158,15 @@ + #define DDB_PORT_NONE 0 + #define DDB_PORT_CI 1 + #define DDB_PORT_TUNER 2 ++#define DDB_PORT_LOOP 3 + u32 type; + #define DDB_TUNER_NONE 0 + #define DDB_TUNER_DVBS_ST 1 + #define DDB_TUNER_DVBS_ST_AA 2 +-#define DDB_TUNER_DVBCT_TR 16 +-#define DDB_TUNER_DVBCT_ST 17 ++#define DDB_TUNER_DVBCT_TR 3 ++#define DDB_TUNER_DVBCT_ST 4 ++#define DDB_CI_INTERNAL 5 ++#define DDB_CI_EXTERNAL_SONY 6 + u32 adr; + + struct ddb_input *input[2]; +@@ -161,25 +181,20 @@ + struct ddb_i2c i2c[DDB_MAX_I2C]; + struct ddb_input input[DDB_MAX_INPUT]; + struct ddb_output output[DDB_MAX_OUTPUT]; ++ struct dvb_adapter adap[DDB_MAX_INPUT]; ++ struct ddb_dma dma[DDB_MAX_INPUT + DDB_MAX_OUTPUT]; + + struct device *ddb_dev; +- int nr; ++ u32 nr; + u8 iobuf[1028]; + + struct ddb_info *info; + int msi; +-}; +- +-/****************************************************************************/ + +-#define ddbwritel(_val, _adr) writel((_val), \ +- (char *) (dev->regs+(_adr))) +-#define ddbreadl(_adr) readl((char *) (dev->regs+(_adr))) +-#define ddbcpyto(_adr, _src, _count) memcpy_toio((char *) \ +- (dev->regs+(_adr)), (_src), (_count)) +-#define ddbcpyfrom(_dst, _adr, _count) memcpy_fromio((_dst), (char *) \ +- (dev->regs+(_adr)), (_count)) ++ u8 leds; + +-/****************************************************************************/ ++ u32 ts_irq; ++ u32 i2c_irq; ++}; + + #endif +diff -Naur linux-3.7.3/drivers/media/pci/ddbridge/ddbridge-regs.h linux-3.7.3.patch/drivers/media/pci/ddbridge/ddbridge-regs.h +--- linux-3.7.3/drivers/media/pci/ddbridge/ddbridge-regs.h 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ddbridge/ddbridge-regs.h 2013-01-20 01:02:55.302829622 +0100 +@@ -21,11 +21,12 @@ + * Or, point your browser to http://www.gnu.org/copyleft/gpl.html + */ + +-/* DD-DVBBridgeV1.h 273 2010-09-17 05:03:16Z manfred */ ++/* DD-DVBBridgeV1.h 388 2011-07-13 20:47:08Z manfred */ + + /* Register Definitions */ + +-#define CUR_REGISTERMAP_VERSION 0x10000 ++#define CUR_REGISTERMAP_VERSION 0x10003 ++#define CUR_REGISTERMAP_VERSION_CI 0x10000 + + #define HARDWARE_VERSION 0x00 + #define REGISTERMAP_VERSION 0x04 +@@ -36,8 +37,14 @@ + #define SPI_CONTROL 0x10 + #define SPI_DATA 0x14 + +-/* ------------------------------------------------------------------------- */ ++/* -------------------------------------------------------------------------- */ ++/* GPIO */ ++ ++#define GPIO_OUTPUT 0x20 ++#define GPIO_INPUT 0x24 ++#define GPIO_DIRECTION 0x28 + ++/* -------------------------------------------------------------------------- */ + /* Interrupt controller */ + /* How many MSI's are available depends on HW (Min 2 max 8) */ + /* How many are usable also depends on Host platform */ +@@ -149,3 +156,46 @@ + #define DMA_BASE_ADDRESS_TABLE (0x2000) + #define DMA_BASE_ADDRESS_TABLE_ENTRIES (512) + ++/* -------------------------------------------------------------------------- */ ++/* CI Interface (only CI-Bridge) */ ++ ++#define CI_BASE (0x400) ++#define CI_CONTROL(i) (CI_BASE + (i) * 32 + 0x00) ++ ++#define CI_DO_ATTRIBUTE_RW(i) (CI_BASE + (i) * 32 + 0x04) ++#define CI_DO_IO_RW(i) (CI_BASE + (i) * 32 + 0x08) ++#define CI_READDATA(i) (CI_BASE + (i) * 32 + 0x0c) ++#define CI_DO_READ_ATTRIBUTES(i) (CI_BASE + (i) * 32 + 0x10) ++ ++#define CI_RESET_CAM (0x00000001) ++#define CI_POWER_ON (0x00000002) ++#define CI_ENABLE (0x00000004) ++#define CI_BLOCKIO_ENABLE (0x00000008) ++#define CI_BYPASS_DISABLE (0x00000010) ++#define CI_DISABLE_AUTO_OFF (0x00000020) ++ ++#define CI_CAM_READY (0x00010000) ++#define CI_CAM_DETECT (0x00020000) ++#define CI_READY (0x80000000) ++#define CI_BLOCKIO_ACTIVE (0x40000000) ++#define CI_BLOCKIO_RCVDATA (0x20000000) ++#define CI_BLOCKIO_SEND_PENDING (0x10000000) ++#define CI_BLOCKIO_SEND_COMPLETE (0x08000000) ++ ++#define CI_READ_CMD (0x40000000) ++#define CI_WRITE_CMD (0x80000000) ++ ++#define CI_BLOCKIO_SEND(i) (CI_BASE + (i) * 32 + 0x14) ++#define CI_BLOCKIO_RECEIVE(i) (CI_BASE + (i) * 32 + 0x18) ++ ++#define CI_BLOCKIO_SEND_COMMAND (0x80000000) ++#define CI_BLOCKIO_SEND_COMPLETE_ACK (0x40000000) ++#define CI_BLOCKIO_RCVDATA_ACK (0x40000000) ++ ++#define CI_BUFFER_BASE (0x3000) ++#define CI_BUFFER_SIZE (0x0800) ++#define CI_BLOCKIO_BUFFER_SIZE (CI_BUFFER_SIZE/2) ++ ++#define CI_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE) ++#define CI_BLOCKIO_RECEIVE_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE) ++#define CI_BLOCKIO_SEND_BUFFER(i) (CI_BUFFER_BASE + (i) * CI_BUFFER_SIZE + CI_BLOCKIO_BUFFER_SIZE) +diff -Naur linux-3.7.3/drivers/media/pci/ddbridge/Kconfig linux-3.7.3.patch/drivers/media/pci/ddbridge/Kconfig +--- linux-3.7.3/drivers/media/pci/ddbridge/Kconfig 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ddbridge/Kconfig 2013-01-20 01:10:50.653800176 +0100 +@@ -1,11 +1,14 @@ + config DVB_DDBRIDGE + tristate "Digital Devices bridge support" + depends on DVB_CORE && PCI && I2C ++ select DVB_CXD2099 + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT + select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT ++ select DVB_STV0367DD if MEDIA_SUBDRV_AUTOSELECT ++ select DVB_TDA18212DD if MEDIA_SUBDRV_AUTOSELECT + ---help--- + Support for cards with the Digital Devices PCI express bridge: + - Octopus PCIe Bridge +@@ -14,5 +17,6 @@ + - DuoFlex S2 Octopus + - DuoFlex CT Octopus + - cineS2(v6) ++ - cineCT(v6) + + Say Y if you own such a card and want to use it. +diff -Naur linux-3.7.3/drivers/media/pci/ngene/Kconfig linux-3.7.3.patch/drivers/media/pci/ngene/Kconfig +--- linux-3.7.3/drivers/media/pci/ngene/Kconfig 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ngene/Kconfig 2013-01-20 01:12:11.930340800 +0100 +@@ -1,6 +1,7 @@ config DVB_NGENE tristate "Micronas nGene support" depends on DVB_CORE && PCI && I2C + select DVB_CXD2099 - select DVB_LNBP21 if !DVB_FE_CUSTOMISE - select DVB_STV6110x if !DVB_FE_CUSTOMISE - select DVB_STV090x if !DVB_FE_CUSTOMISE - select DVB_LGDT330X if !DVB_FE_CUSTOMISE - select DVB_DRXK if !DVB_FE_CUSTOMISE - select DVB_TDA18271C2DD if !DVB_FE_CUSTOMISE -+ select DVB_STV0367DD if !DVB_FE_CUSTOMISE -+ select DVB_TDA18212DD if !DVB_FE_CUSTOMISE - select MEDIA_TUNER_MT2131 if !MEDIA_TUNER_CUSTOMISE + select DVB_LNBP21 if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV6110x if MEDIA_SUBDRV_AUTOSELECT + select DVB_STV090x if MEDIA_SUBDRV_AUTOSELECT +@@ -8,6 +9,8 @@ + select DVB_DRXK if MEDIA_SUBDRV_AUTOSELECT + select DVB_TDA18271C2DD if MEDIA_SUBDRV_AUTOSELECT + select MEDIA_TUNER_MT2131 if MEDIA_SUBDRV_AUTOSELECT ++ select DVB_STV0367DD if MEDIA_SUBDRV_AUTOSELECT ++ select DVB_TDA18212DD if MEDIA_SUBDRV_AUTOSELECT ---help--- Support for Micronas PCI express cards with nGene bridge. -diff -Naur linux-3.6.8/drivers/media/dvb/ngene/Makefile linux-3.6.8.patch/drivers/media/dvb/ngene/Makefile ---- linux-3.6.8/drivers/media/dvb/ngene/Makefile 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ngene/Makefile 2012-12-03 08:58:39.951117965 +0100 + +diff -Naur linux-3.7.3/drivers/media/pci/ngene/Makefile linux-3.7.3.patch/drivers/media/pci/ngene/Makefile +--- linux-3.7.3/drivers/media/pci/ngene/Makefile 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ngene/Makefile 2013-01-20 01:05:04.979910075 +0100 @@ -2,7 +2,8 @@ # Makefile for the nGene device driver # @@ -9652,9 +9639,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/Makefile linux-3.6.8.patch/driver obj-$(CONFIG_DVB_NGENE) += ngene.o -diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-av.c linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-av.c ---- linux-3.6.8/drivers/media/dvb/ngene/ngene-av.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-av.c 2012-12-03 09:06:17.133472933 +0100 +diff -Naur linux-3.7.3/drivers/media/pci/ngene/ngene-av.c linux-3.7.3.patch/drivers/media/pci/ngene/ngene-av.c +--- linux-3.7.3/drivers/media/pci/ngene/ngene-av.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ngene/ngene-av.c 2013-01-20 01:05:04.980910068 +0100 @@ -0,0 +1,348 @@ +/* + * ngene-av.c: nGene PCIe bridge driver - DVB video/audio support @@ -10004,19 +9991,19 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-av.c linux-3.6.8.patch/driv + .fops = &video_fops, +}; +#endif -diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-cards.c linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-cards.c ---- linux-3.6.8/drivers/media/dvb/ngene/ngene-cards.c 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-cards.c 2012-12-03 09:06:30.239367796 +0100 -@@ -42,6 +42,8 @@ - #include "mt2131.h" - #include "tda18271c2dd.h" +diff -Naur linux-3.7.3/drivers/media/pci/ngene/ngene-cards.c linux-3.7.3.patch/drivers/media/pci/ngene/ngene-cards.c +--- linux-3.7.3/drivers/media/pci/ngene/ngene-cards.c 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ngene/ngene-cards.c 2013-01-20 01:15:24.833266247 +0100 +@@ -44,6 +44,8 @@ #include "drxk.h" + #include "drxd.h" + #include "dvb-pll.h" +#include "tda18212dd.h" +#include "stv0367dd.h" /****************************************************************************/ -@@ -84,8 +86,98 @@ +@@ -86,8 +88,98 @@ return 0; } @@ -10116,7 +10103,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-cards.c linux-3.6.8.patch/d { struct ngene_channel *chan = fe->sec_priv; int status; -@@ -119,12 +211,29 @@ +@@ -121,12 +213,29 @@ return 0; } @@ -10146,7 +10133,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-cards.c linux-3.6.8.patch/d return -EINVAL; } -@@ -216,18 +325,51 @@ +@@ -218,18 +327,51 @@ struct drxk_config config; memset(&config, 0, sizeof(config)); @@ -10201,7 +10188,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-cards.c linux-3.6.8.patch/d return 0; } -@@ -277,6 +419,9 @@ +@@ -279,6 +421,9 @@ } else if (port_has_drxk(i2c, chan->number^2)) { chan->demod_type = 1; demod_attach_drxk(chan, i2c); @@ -10211,7 +10198,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-cards.c linux-3.6.8.patch/d } else { printk(KERN_ERR "No demod found on chan %d\n", chan->number); return -ENODEV; -@@ -317,6 +462,136 @@ +@@ -548,6 +693,136 @@ /* Switch control (I2C gates, etc.) *****************************************/ /****************************************************************************/ @@ -10348,7 +10335,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-cards.c linux-3.6.8.patch/d static struct stv090x_config fe_cineS2 = { .device = STV0900, -@@ -466,6 +741,323 @@ +@@ -728,6 +1003,323 @@ /****************************************************************************/ @@ -10672,7 +10659,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-cards.c linux-3.6.8.patch/d /****************************************************************************/ -@@ -480,6 +1072,8 @@ +@@ -742,6 +1334,8 @@ /****************************************************************************/ static const struct pci_device_id ngene_id_tbl[] __devinitdata = { @@ -10681,16 +10668,15 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-cards.c linux-3.6.8.patch/d NGENE_ID(0x18c3, 0xabc3, ngene_info_cineS2), NGENE_ID(0x18c3, 0xabc4, ngene_info_cineS2), NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2), -@@ -488,6 +1082,32 @@ - NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlex), +@@ -751,6 +1345,31 @@ NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlex), NGENE_ID(0x1461, 0x062e, ngene_info_m780), + NGENE_ID(0x153b, 0x1167, ngene_info_terratec), +#if 0 /* not (yet?) supported */ + NGENE_ID(0x18c3, 0x0000, ngene_info_appboard), + NGENE_ID(0x18c3, 0x0004, ngene_info_appboard), + NGENE_ID(0x18c3, 0x8011, ngene_info_appboard), + NGENE_ID(0x18c3, 0x8015, ngene_info_appboard_ntsc), -+ NGENE_ID(0x153b, 0x1167, ngene_info_terratec), + NGENE_ID(0x18c3, 0x0030, ngene_info_python), + NGENE_ID(0x18c3, 0x0052, ngene_info_sidewinder), + NGENE_ID(0x18c3, 0x8f00, ngene_info_racer), @@ -10714,9 +10700,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-cards.c linux-3.6.8.patch/d {0} }; MODULE_DEVICE_TABLE(pci, ngene_id_tbl); -diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-core.c ---- linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-core.c 2012-12-03 09:06:06.341559356 +0100 +diff -Naur linux-3.7.3/drivers/media/pci/ngene/ngene-core.c linux-3.7.3.patch/drivers/media/pci/ngene/ngene-core.c +--- linux-3.7.3/drivers/media/pci/ngene/ngene-core.c 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ngene/ngene-core.c 2013-01-20 01:05:31.105738963 +0100 @@ -86,6 +86,14 @@ if ((Event.UARTStatus & 0x02) && (dev->RxEventNotify)) dev->RxEventNotify(dev, Event.TimeStamp, @@ -10746,7 +10732,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr if (nextWriteIndex != dev->EventQueueReadIndex) { dev->EventQueue[dev->EventQueueWriteIndex] = *(dev->EventBuffer); -@@ -322,12 +337,24 @@ +@@ -316,12 +331,24 @@ ngwritel(1, FORCE_INT); ret = wait_event_timeout(dev->cmd_wq, dev->cmd_done == 1, 2 * HZ); @@ -10771,7 +10757,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr dump_command_io(dev); return -1; } -@@ -354,6 +381,19 @@ +@@ -348,6 +375,19 @@ return result; } @@ -10791,7 +10777,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr static int ngene_command_load_firmware(struct ngene *dev, u8 *ngene_fw, u32 size) -@@ -388,6 +428,83 @@ +@@ -382,6 +422,83 @@ return ngene_command(dev, &com); } @@ -10875,7 +10861,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr static int ngene_command_config_buf(struct ngene *dev, u8 config) { -@@ -433,6 +550,18 @@ +@@ -427,6 +544,18 @@ return ngene_command(dev, &com); } @@ -10894,7 +10880,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr /* 02000640 is sample on rising edge. -@@ -518,6 +647,17 @@ +@@ -512,6 +641,17 @@ } } @@ -10912,7 +10898,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr static void flush_buffers(struct ngene_channel *chan) { -@@ -738,6 +878,14 @@ +@@ -732,6 +872,14 @@ if (dev->card_info->switch_ctrl) dev->card_info->switch_ctrl(chan, 1, state ^ 1); @@ -10927,7 +10913,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr if (state) { spin_lock_irq(&chan->state_lock); -@@ -777,6 +925,89 @@ +@@ -771,6 +919,89 @@ } } @@ -11017,7 +11003,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr /****************************************************************************/ /* nGene hardware init and release functions ********************************/ -@@ -1071,6 +1302,85 @@ +@@ -1065,6 +1296,85 @@ 0 }; @@ -11103,7 +11089,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr static int AllocCommonBuffers(struct ngene *dev) { -@@ -1324,6 +1634,10 @@ +@@ -1318,6 +1628,10 @@ u8 tsin12_config[6] = { 0x60, 0x60, 0x00, 0x00, 0x00, 0x00 }; u8 tsin1234_config[6] = { 0x30, 0x30, 0x00, 0x30, 0x30, 0x00 }; u8 tsio1235_config[6] = { 0x30, 0x30, 0x00, 0x28, 0x00, 0x38 }; @@ -11114,7 +11100,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr u8 *bconf = tsin12_config; if (dev->card_info->io_type[2]&NGENE_IO_TSIN && -@@ -1333,10 +1647,22 @@ +@@ -1327,10 +1641,22 @@ dev->ci.en) bconf = tsio1235_config; } @@ -11137,7 +11123,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr if (dev->card_info->io_type[3] == NGENE_IO_TSIN) bconf = BUFFER_CONFIG_3333; stat = ngene_command_config_buf(dev, bconf); -@@ -1409,8 +1735,10 @@ +@@ -1403,8 +1729,10 @@ if (stat < 0) goto fail; @@ -11149,7 +11135,7 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr fail: ngwritel(0, NGENE_INT_ENABLE); free_irq(dev->pci_dev->irq, dev); -@@ -1695,6 +2023,33 @@ +@@ -1689,6 +2017,33 @@ dev->i2c_current_bus = -1; @@ -11183,9 +11169,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-core.c linux-3.6.8.patch/dr /* Register DVB adapters and devices for both channels */ if (init_channels(dev) < 0) -diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-dvb.c linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-dvb.c ---- linux-3.6.8/drivers/media/dvb/ngene/ngene-dvb.c 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-dvb.c 2012-12-03 09:05:52.497670334 +0100 +diff -Naur linux-3.7.3/drivers/media/pci/ngene/ngene-dvb.c linux-3.7.3.patch/drivers/media/pci/ngene/ngene-dvb.c +--- linux-3.7.3/drivers/media/pci/ngene/ngene-dvb.c 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ngene/ngene-dvb.c 2013-01-20 01:05:46.293640625 +0100 @@ -42,10 +42,319 @@ #include "ngene.h" @@ -11596,9 +11582,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-dvb.c linux-3.6.8.patch/dri if (--chan->users) return chan->users; -diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-eeprom.c linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-eeprom.c ---- linux-3.6.8/drivers/media/dvb/ngene/ngene-eeprom.c 1970-01-01 01:00:00.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-eeprom.c 2012-12-03 08:41:17.000000000 +0100 +diff -Naur linux-3.7.3/drivers/media/pci/ngene/ngene-eeprom.c linux-3.7.3.patch/drivers/media/pci/ngene/ngene-eeprom.c +--- linux-3.7.3/drivers/media/pci/ngene/ngene-eeprom.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ngene/ngene-eeprom.c 2013-01-20 01:05:46.293640625 +0100 @@ -0,0 +1,284 @@ +/* + * ngene-eeprom.c: nGene PCIe bridge driver - eeprom support @@ -11884,9 +11870,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-eeprom.c linux-3.6.8.patch/ +} + +#endif -diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene.h linux-3.6.8.patch/drivers/media/dvb/ngene/ngene.h ---- linux-3.6.8/drivers/media/dvb/ngene/ngene.h 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ngene/ngene.h 2012-12-03 08:41:17.000000000 +0100 +diff -Naur linux-3.7.3/drivers/media/pci/ngene/ngene.h linux-3.7.3.patch/drivers/media/pci/ngene/ngene.h +--- linux-3.7.3/drivers/media/pci/ngene/ngene.h 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ngene/ngene.h 2013-01-20 01:05:59.311556814 +0100 @@ -653,6 +653,11 @@ struct dmx_frontend mem_frontend; int users; @@ -11962,9 +11948,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene.h linux-3.6.8.patch/drivers #endif /* LocalWords: Endif -diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-i2c.c linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-i2c.c ---- linux-3.6.8/drivers/media/dvb/ngene/ngene-i2c.c 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/media/dvb/ngene/ngene-i2c.c 2012-12-03 09:05:39.359775326 +0100 +diff -Naur linux-3.7.3/drivers/media/pci/ngene/ngene-i2c.c linux-3.7.3.patch/drivers/media/pci/ngene/ngene-i2c.c +--- linux-3.7.3/drivers/media/pci/ngene/ngene-i2c.c 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/media/pci/ngene/ngene-i2c.c 2013-01-20 01:06:08.210499977 +0100 @@ -77,6 +77,11 @@ { struct ngene_command com; @@ -12096,9 +12082,9 @@ diff -Naur linux-3.6.8/drivers/media/dvb/ngene/ngene-i2c.c linux-3.6.8.patch/dri +} + +#endif -diff -Naur linux-3.6.8/drivers/staging/media/cxd2099/cxd2099.c linux-3.6.8.patch/drivers/staging/media/cxd2099/cxd2099.c ---- linux-3.6.8/drivers/staging/media/cxd2099/cxd2099.c 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/staging/media/cxd2099/cxd2099.c 2012-12-03 08:41:17.000000000 +0100 +diff -Naur linux-3.7.3/drivers/staging/media/cxd2099/cxd2099.c linux-3.7.3.patch/drivers/staging/media/cxd2099/cxd2099.c +--- linux-3.7.3/drivers/staging/media/cxd2099/cxd2099.c 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/staging/media/cxd2099/cxd2099.c 2013-01-20 01:06:08.210499977 +0100 @@ -117,9 +117,10 @@ static int read_block(struct cxd *ci, u8 adr, u8 *data, u8 n) @@ -12112,21 +12098,21 @@ diff -Naur linux-3.6.8/drivers/staging/media/cxd2099/cxd2099.c linux-3.6.8.patch if (!status) { ci->lastaddress = adr; status = i2c_read(ci->i2c, ci->cfg.adr, 1, data, n); -diff -Naur linux-3.6.8/drivers/staging/media/cxd2099/Makefile linux-3.6.8.patch/drivers/staging/media/cxd2099/Makefile ---- linux-3.6.8/drivers/staging/media/cxd2099/Makefile 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/staging/media/cxd2099/Makefile 2012-12-03 08:41:17.000000000 +0100 +diff -Naur linux-3.7.3/drivers/staging/media/cxd2099/Makefile linux-3.7.3.patch/drivers/staging/media/cxd2099/Makefile +--- linux-3.7.3/drivers/staging/media/cxd2099/Makefile 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/staging/media/cxd2099/Makefile 2013-01-20 01:08:53.879482088 +0100 @@ -1,5 +1,5 @@ obj-$(CONFIG_DVB_CXD2099) += cxd2099.o --ccflags-y += -Idrivers/media/dvb/dvb-core/ --ccflags-y += -Idrivers/media/dvb/frontends/ --ccflags-y += -Idrivers/media/common/tuners/ -+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends/ -+EXTRA_CFLAGS += -Idrivers/media/common/tuners/ -diff -Naur linux-3.6.8/drivers/staging/media/cxd2099/TODO linux-3.6.8.patch/drivers/staging/media/cxd2099/TODO ---- linux-3.6.8/drivers/staging/media/cxd2099/TODO 2012-11-26 21:15:45.000000000 +0100 -+++ linux-3.6.8.patch/drivers/staging/media/cxd2099/TODO 1970-01-01 01:00:00.000000000 +0100 +-ccflags-y += -Idrivers/media/dvb-core/ +-ccflags-y += -Idrivers/media/dvb-frontends/ +-ccflags-y += -Idrivers/media/tuners/ ++EXTRA_CFLAGS += -Idrivers/media/dvb-core/ ++EXTRA_CFLAGS += -Idrivers/media/dvb-frontends/ ++EXTRA_CFLAGS += -Idrivers/media/tuners/ +diff -Naur linux-3.7.3/drivers/staging/media/cxd2099/TODO linux-3.7.3.patch/drivers/staging/media/cxd2099/TODO +--- linux-3.7.3/drivers/staging/media/cxd2099/TODO 2013-01-17 17:47:40.000000000 +0100 ++++ linux-3.7.3.patch/drivers/staging/media/cxd2099/TODO 1970-01-01 01:00:00.000000000 +0100 @@ -1,12 +0,0 @@ -For now, data is passed through '/dev/dvb/adapterX/sec0': - - Encrypted data must be written to 'sec0'.