mirror of
https://github.com/DigitalDevices/dddvb.git
synced 2025-03-01 10:35:23 +00:00
initial commit from dddvb-0.9.19c
This commit is contained in:
8
ddbridge/Kbuild
Normal file
8
ddbridge/Kbuild
Normal file
@@ -0,0 +1,8 @@
|
||||
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843 -DCONFIG_DVB_LNBP21 -DCONFIG_DVB_STV090x -DCONFIG_DVB_STV6110x -DCONFIG_DVB_DRXK -DCONFIG_DVB_STV0910 -DCONFIG_DVB_STV6111 -DCONFIG_DVB_LNBH25 -DCONFIG_DVB_MXL5XX
|
||||
|
||||
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
|
||||
obj-$(CONFIG_DVB_OCTONET) += octonet.o
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends
|
||||
EXTRA_CFLAGS += -Idrivers/media/common/tuners
|
||||
NOSTDINC_FLAGS += -I$(SUBDIRS)/frontends -I$(SUBDIRS)/include -I$(SUBDIRS)/dvb-core
|
19
ddbridge/Makefile
Normal file
19
ddbridge/Makefile
Normal file
@@ -0,0 +1,19 @@
|
||||
KDIR ?= /lib/modules/$(shell uname -r)/build
|
||||
PWD := $(shell pwd)
|
||||
|
||||
MODDEFS := CONFIG_DVB_DDBRIDGE=m
|
||||
|
||||
all:
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) $(MODDEFS) modules
|
||||
$(MAKE) -C apps
|
||||
|
||||
dep:
|
||||
DIR=`pwd`; (cd $(TOPDIR); make SUBDIRS=$$DIR dep)
|
||||
|
||||
install: all
|
||||
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules_install
|
||||
|
||||
clean:
|
||||
rm -rf */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*
|
||||
|
||||
|
4641
ddbridge/ddbridge-core.c
Normal file
4641
ddbridge/ddbridge-core.c
Normal file
File diff suppressed because it is too large
Load Diff
275
ddbridge/ddbridge-i2c.c
Normal file
275
ddbridge/ddbridge-i2c.c
Normal file
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* ddbridge-i2c.c: Digital Devices bridge i2c driver
|
||||
*
|
||||
* Copyright (C) 2010-2015 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
static int i2c_io(struct i2c_adapter *adapter, u8 adr,
|
||||
u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
|
||||
{
|
||||
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
|
||||
.buf = wbuf, .len = wlen },
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = rbuf, .len = rlen } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
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,
|
||||
.buf = val, .len = 1 } };
|
||||
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 = reg16, .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},
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = val, .len = 1 } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
|
||||
u16 reg, u8 *val)
|
||||
{
|
||||
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 } };
|
||||
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 i2c_write_reg(struct i2c_adapter *adap, u8 adr,
|
||||
u8 reg, u8 val)
|
||||
{
|
||||
u8 msg[2] = {reg, val};
|
||||
|
||||
return i2c_write(adap, adr, msg, 2);
|
||||
}
|
||||
|
||||
static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
|
||||
{
|
||||
struct ddb *dev = i2c->dev;
|
||||
unsigned long stat;
|
||||
u32 val;
|
||||
|
||||
ddbwritel(dev, (adr << 9) | cmd, i2c->regs + I2C_COMMAND);
|
||||
stat = wait_for_completion_timeout(&i2c->completion, HZ);
|
||||
if (stat == 0) {
|
||||
pr_err("DDBridge I2C timeout, card %d, port %d, link %u\n",
|
||||
dev->nr, i2c->nr, i2c->link);
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
{ /* MSI debugging*/
|
||||
u32 istat = ddbreadl(dev, INTERRUPT_STATUS);
|
||||
|
||||
dev_err(dev->dev, "DDBridge IRS %08x\n", istat);
|
||||
ddbwritel(dev, istat, INTERRUPT_ACK);
|
||||
}
|
||||
#endif
|
||||
return -EIO;
|
||||
}
|
||||
val = ddbreadl(dev, i2c->regs + I2C_COMMAND);
|
||||
if (val & 0x70000)
|
||||
return -EIO;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 *dev = i2c->dev;
|
||||
u8 addr = 0;
|
||||
|
||||
if (num != 1 && num != 2)
|
||||
return -EIO;
|
||||
addr = msg[0].addr;
|
||||
if (msg[0].len > i2c->bsize)
|
||||
return -EIO;
|
||||
if (num == 2 && msg[1].flags & I2C_M_RD &&
|
||||
!(msg[0].flags & I2C_M_RD)) {
|
||||
if (msg[1].len > i2c->bsize)
|
||||
return -EIO;
|
||||
ddbcpyto(dev, i2c->wbuf, msg[0].buf, msg[0].len);
|
||||
ddbwritel(dev, msg[0].len | (msg[1].len << 16),
|
||||
i2c->regs + I2C_TASKLENGTH);
|
||||
if (!ddb_i2c_cmd(i2c, addr, 1)) {
|
||||
ddbcpyfrom(dev, msg[1].buf,
|
||||
i2c->rbuf,
|
||||
msg[1].len);
|
||||
return num;
|
||||
}
|
||||
}
|
||||
if (num == 1 && !(msg[0].flags & I2C_M_RD)) {
|
||||
ddbcpyto(dev, 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(dev, msg[0].len << 16, i2c->regs + I2C_TASKLENGTH);
|
||||
if (!ddb_i2c_cmd(i2c, addr, 3)) {
|
||||
ddbcpyfrom(dev, msg[0].buf,
|
||||
i2c->rbuf, msg[0].len);
|
||||
return num;
|
||||
}
|
||||
}
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static u32 ddb_i2c_functionality(struct i2c_adapter *adap)
|
||||
{
|
||||
return I2C_FUNC_I2C | I2C_FUNC_SMBUS_EMUL;
|
||||
}
|
||||
|
||||
struct i2c_algorithm ddb_i2c_algo = {
|
||||
.master_xfer = ddb_i2c_master_xfer,
|
||||
.functionality = ddb_i2c_functionality,
|
||||
};
|
||||
|
||||
static void ddb_i2c_release(struct ddb *dev)
|
||||
{
|
||||
int i;
|
||||
struct ddb_i2c *i2c;
|
||||
|
||||
for (i = 0; i < dev->i2c_num; i++) {
|
||||
i2c = &dev->i2c[i];
|
||||
i2c_del_adapter(&i2c->adap);
|
||||
}
|
||||
}
|
||||
|
||||
static void i2c_handler(unsigned long priv)
|
||||
{
|
||||
struct ddb_i2c *i2c = (struct ddb_i2c *) priv;
|
||||
|
||||
complete(&i2c->completion);
|
||||
}
|
||||
|
||||
static int ddb_i2c_add(struct ddb *dev, struct ddb_i2c *i2c,
|
||||
struct ddb_regmap *regmap, int link, int i, int num)
|
||||
{
|
||||
struct i2c_adapter *adap;
|
||||
|
||||
i2c->nr = i;
|
||||
i2c->dev = dev;
|
||||
i2c->link = link;
|
||||
i2c->bsize = regmap->i2c_buf->size;
|
||||
i2c->wbuf = DDB_LINK_TAG(link) | (regmap->i2c_buf->base + i2c->bsize * i);
|
||||
i2c->rbuf = i2c->wbuf;// + i2c->bsize / 2;
|
||||
i2c->regs = DDB_LINK_TAG(link) | (regmap->i2c->base + regmap->i2c->size * i);
|
||||
ddbwritel(dev, I2C_SPEED_100, i2c->regs + I2C_TIMING);
|
||||
ddbwritel(dev, ((i2c->rbuf & 0xffff) << 16) | (i2c->wbuf & 0xffff),
|
||||
i2c->regs + I2C_TASKADDRESS);
|
||||
init_completion(&i2c->completion);
|
||||
|
||||
adap = &i2c->adap;
|
||||
i2c_set_adapdata(adap, i2c);
|
||||
#ifdef I2C_ADAP_CLASS_TV_DIGITAL
|
||||
adap->class = I2C_ADAP_CLASS_TV_DIGITAL|I2C_CLASS_TV_ANALOG;
|
||||
#else
|
||||
#ifdef I2C_CLASS_TV_ANALOG
|
||||
adap->class = I2C_CLASS_TV_ANALOG;
|
||||
#endif
|
||||
#endif
|
||||
strcpy(adap->name, "ddbridge");
|
||||
adap->algo = &ddb_i2c_algo;
|
||||
adap->algo_data = (void *)i2c;
|
||||
adap->dev.parent = dev->dev;
|
||||
return i2c_add_adapter(adap);
|
||||
}
|
||||
|
||||
static int ddb_i2c_init(struct ddb *dev)
|
||||
{
|
||||
int stat = 0;
|
||||
u32 i, j, num = 0, l;
|
||||
struct ddb_i2c *i2c;
|
||||
struct i2c_adapter *adap;
|
||||
struct ddb_regmap *regmap;
|
||||
|
||||
for (l = 0; l < DDB_MAX_LINK; l++) {
|
||||
if (!dev->link[l].info)
|
||||
continue;
|
||||
regmap = dev->link[l].info->regmap;
|
||||
if (!regmap || !regmap->i2c)
|
||||
continue;
|
||||
for (i = 0; i < regmap->i2c->num; i++) {
|
||||
if (!(dev->link[l].info->i2c_mask & (1 << i)))
|
||||
continue;
|
||||
i2c = &dev->i2c[num];
|
||||
dev->handler_data[i + l * 32] = (unsigned long) i2c;
|
||||
dev->handler[i + l * 32] = i2c_handler;
|
||||
stat = ddb_i2c_add(dev, i2c, regmap, l, i, num);
|
||||
if (stat)
|
||||
break;
|
||||
num++;
|
||||
}
|
||||
}
|
||||
if (stat) {
|
||||
for (j = 0; j < num; j++) {
|
||||
i2c = &dev->i2c[j];
|
||||
adap = &i2c->adap;
|
||||
i2c_del_adapter(adap);
|
||||
}
|
||||
} else
|
||||
dev->i2c_num = num;
|
||||
return stat;
|
||||
}
|
||||
|
116
ddbridge/ddbridge-i2c.h
Normal file
116
ddbridge/ddbridge-i2c.h
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* ddbridge-i2c.h: Digital Devices bridge i2c driver
|
||||
*
|
||||
* Copyright (C) 2010-2015 Digital Devices GmbH
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#ifndef _DDBRIDGE_I2C_H_
|
||||
#define _DDBRIDGE_I2C_H_
|
||||
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/types.h>
|
||||
|
||||
static inline int i2c_io(struct i2c_adapter *adapter, u8 adr,
|
||||
u8 *wbuf, u32 wlen, u8 *rbuf, u32 rlen)
|
||||
{
|
||||
struct i2c_msg msgs[2] = {{.addr = adr, .flags = 0,
|
||||
.buf = wbuf, .len = wlen },
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = rbuf, .len = rlen } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline 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 inline int i2c_read(struct i2c_adapter *adapter, u8 adr, u8 *val)
|
||||
{
|
||||
struct i2c_msg msgs[1] = {{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = val, .len = 1 } };
|
||||
return (i2c_transfer(adapter, msgs, 1) == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline 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 inline 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 = reg16, .len = 2 },
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = val, .len = len } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline 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},
|
||||
{.addr = adr, .flags = I2C_M_RD,
|
||||
.buf = val, .len = 1 } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline int i2c_read_reg16(struct i2c_adapter *adapter, u8 adr,
|
||||
u16 reg, u8 *val)
|
||||
{
|
||||
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 } };
|
||||
return (i2c_transfer(adapter, msgs, 2) == 2) ? 0 : -1;
|
||||
}
|
||||
|
||||
static inline 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 inline int i2c_write_reg(struct i2c_adapter *adap, u8 adr,
|
||||
u8 reg, u8 val)
|
||||
{
|
||||
u8 msg[2] = {reg, val};
|
||||
|
||||
return i2c_write(adap, adr, msg, 2);
|
||||
}
|
||||
|
||||
#endif
|
1150
ddbridge/ddbridge-mod.c
Normal file
1150
ddbridge/ddbridge-mod.c
Normal file
File diff suppressed because it is too large
Load Diff
491
ddbridge/ddbridge-ns.c
Normal file
491
ddbridge/ddbridge-ns.c
Normal file
@@ -0,0 +1,491 @@
|
||||
/*
|
||||
* ddbridge-ns.c: Digital Devices PCIe bridge driver net streaming
|
||||
*
|
||||
* Copyright (C) 2010-2015 Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Digital Devices GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
static int ddb_dvb_ns_input_start(struct ddb_input *input);
|
||||
static int ddb_dvb_ns_input_stop(struct ddb_input *input);
|
||||
|
||||
static u16 calc_pcs(struct dvb_ns_params *p)
|
||||
{
|
||||
u32 sum = 0;
|
||||
u16 pcs;
|
||||
|
||||
sum += (p->sip[0] << 8) | p->sip[1];
|
||||
sum += (p->sip[2] << 8) | p->sip[3];
|
||||
sum += (p->dip[0] << 8) | p->dip[1];
|
||||
sum += (p->dip[2] << 8) | p->dip[3];
|
||||
sum += 0x11; /* UDP proto */
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
pcs = sum;
|
||||
return pcs;
|
||||
}
|
||||
|
||||
static u16 calc_pcs16(struct dvb_ns_params *p, int ipv)
|
||||
{
|
||||
u32 sum = 0, i;
|
||||
u16 pcs;
|
||||
|
||||
for (i = 0; i < ipv ? 16 : 4; i += 2) {
|
||||
sum += (p->sip[i] << 8) | p->sip[i + 1];
|
||||
sum += (p->dip[i] << 8) | p->dip[i + 1];
|
||||
}
|
||||
sum += 0x11; /* UDP proto */
|
||||
sum = (sum >> 16) + (sum & 0xffff);
|
||||
pcs = sum;
|
||||
return pcs;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static void ns_free(struct dvbnss *nss)
|
||||
{
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
dns->input = 0;
|
||||
mutex_unlock(&dev->mutex);
|
||||
}
|
||||
|
||||
static int ns_alloc(struct dvbnss *nss)
|
||||
{
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
int i, ret = -EBUSY;
|
||||
|
||||
mutex_lock(&dev->mutex);
|
||||
for (i = 0; i < dev->ns_num; i++) {
|
||||
if (dev->ns[i].input)
|
||||
continue;
|
||||
dev->ns[i].input = input;
|
||||
dev->ns[i].fe = input;
|
||||
nss->priv = &dev->ns[i];
|
||||
ret = 0;
|
||||
/*pr_info("%s i=%d fe=%d\n", __func__, i, input->nr); */
|
||||
break;
|
||||
}
|
||||
ddbwritel(dev, 0x03, RTP_MASTER_CONTROL);
|
||||
mutex_unlock(&dev->mutex);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ns_set_pids(struct dvbnss *nss)
|
||||
{
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
|
||||
if (dev->ids.devid == 0x0301dd01) {
|
||||
u32 sys = 0;
|
||||
int pid, j = 1;
|
||||
|
||||
sys |= nss->pids[0] & 3;
|
||||
sys |= (nss->pids[2] & 0x1f) << 4;
|
||||
ddbwritel(dev, sys, PID_FILTER_SYSTEM_PIDS(dns->nr));
|
||||
for (pid = 20; j < 5 && pid < 8192; pid++)
|
||||
if (nss->pids[pid >> 3] & (1 << (pid & 7))) {
|
||||
ddbwritel(dev, 0x8000 | pid,
|
||||
PID_FILTER_PID(dns->nr, j));
|
||||
j++;
|
||||
}
|
||||
/* disable unused pids */
|
||||
for (; j < 5; j++)
|
||||
ddbwritel(dev, 0, PID_FILTER_PID(dns->nr, j));
|
||||
} else
|
||||
ddbcpyto(dev, STREAM_PIDS(dns->nr), nss->pids, 0x400);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ns_set_pid(struct dvbnss *nss, u16 pid)
|
||||
{
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
u16 byte = (pid & 0x1fff) >> 3;
|
||||
u8 bit = 1 << (pid & 7);
|
||||
u32 off = STREAM_PIDS(dns->nr);
|
||||
|
||||
#if 1
|
||||
if (dev->ids.devid == 0x0301dd01) {
|
||||
if (pid & 0x2000) {
|
||||
if (pid & 0x8000)
|
||||
memset(nss->pids, 0xff, 0x400);
|
||||
else
|
||||
memset(nss->pids, 0x00, 0x400);
|
||||
} else {
|
||||
if (pid & 0x8000)
|
||||
nss->pids[byte] |= bit;
|
||||
else
|
||||
nss->pids[byte] &= ~bit;
|
||||
}
|
||||
ns_set_pids(nss);
|
||||
} else {
|
||||
if (pid & 0x2000) {
|
||||
if (pid & 0x8000)
|
||||
ddbmemset(dev, off, 0xff, 0x400);
|
||||
else
|
||||
ddbmemset(dev, off, 0x00, 0x400);
|
||||
} else {
|
||||
u8 val = ddbreadb(dev, off + byte);
|
||||
|
||||
if (pid & 0x8000)
|
||||
ddbwriteb(dev, val | bit, off + byte);
|
||||
else
|
||||
ddbwriteb(dev, val & ~bit, off + byte);
|
||||
}
|
||||
}
|
||||
#else
|
||||
ddbcpyto(dev, STREAM_PIDS(dns->nr), nss->pids, 0x400);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int citoport(struct ddb *dev, u8 ci)
|
||||
{
|
||||
int i, j;
|
||||
|
||||
for (i = j = 0; i < dev->link[0].info->port_num; i++) {
|
||||
if (dev->port[i].class == DDB_PORT_CI) {
|
||||
if (j == ci)
|
||||
return i;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int ns_set_ci(struct dvbnss *nss, u8 ci)
|
||||
{
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
int ciport;
|
||||
|
||||
if (ci == 255) {
|
||||
dns->fe = input;
|
||||
return 0;
|
||||
}
|
||||
ciport = citoport(dev, ci);
|
||||
if (ciport < 0)
|
||||
return -EINVAL;
|
||||
|
||||
pr_info("input %d.%d to ci %d at port %d\n", input->port->lnr, input->nr, ci, ciport);
|
||||
ddbwritel(dev, (input->port->lnr << 21) | (input->nr << 16) | 0x1c, TS_OUTPUT_CONTROL(ciport));
|
||||
usleep_range(1, 5);
|
||||
ddbwritel(dev, (input->port->lnr << 21) | (input->nr << 16) | 0x1d, TS_OUTPUT_CONTROL(ciport));
|
||||
dns->fe = dev->port[ciport].input[0];
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 rtp_head[] = {
|
||||
0x80, 0x21,
|
||||
0x00, 0x00, /* seq number */
|
||||
0x00, 0x00, 0x00, 0x00, /* time stamp*/
|
||||
0x91, 0x82, 0x73, 0x64, /* SSRC */
|
||||
};
|
||||
|
||||
static u8 rtcp_head[] = {
|
||||
/* SR off 42:8 len 28*/
|
||||
0x80, 0xc8, /* SR type */
|
||||
0x00, 0x06, /* len */
|
||||
0x91, 0x82, 0x73, 0x64, /* SSRC */
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* NTP */
|
||||
0x73, 0x64, 0x00, 0x00, /* RTP TS */
|
||||
0x00, 0x00, 0x00, 0x00, /* packet count */
|
||||
0x00, 0x00, 0x00, 0x00, /* octet count */
|
||||
/* SDES off 70:36 len 20 */
|
||||
0x81, 0xca, /* SDES */
|
||||
0x00, 0x03, /* len */
|
||||
0x91, 0x82, 0x73, 0x64, /* SSRC */
|
||||
0x01, 0x05, /* CNAME item */
|
||||
0x53, 0x41, 0x54, 0x49, 0x50, /* "SATIP" */
|
||||
0x00, /* item type 0 */
|
||||
/* APP off 86:52 len 16+string length */
|
||||
0x80, 0xcc, /* APP */
|
||||
0x00, 0x04, /* len */
|
||||
0x91, 0x82, 0x73, 0x64, /* SSRC */
|
||||
0x53, 0x45, 0x53, 0x31, /* "SES1" */
|
||||
0x00, 0x00, /* identifier */
|
||||
0x00, 0x00, /* string length */
|
||||
/* string off 102:68 */
|
||||
};
|
||||
|
||||
static int ns_set_rtcp_msg(struct dvbnss *nss, u8 *msg, u32 len)
|
||||
{
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
u32 off = STREAM_PACKET_ADR(dns->nr);
|
||||
u32 coff = 96;
|
||||
u16 wlen;
|
||||
|
||||
if (!len) {
|
||||
ddbwritel(dev, ddbreadl(dev, STREAM_CONTROL(dns->nr)) &
|
||||
~0x10,
|
||||
STREAM_CONTROL(dns->nr));
|
||||
return 0;
|
||||
}
|
||||
if (copy_from_user(dns->p + coff + dns->rtcp_len, msg, len))
|
||||
return -EFAULT;
|
||||
dns->p[coff + dns->rtcp_len - 2] = (len >> 8);
|
||||
dns->p[coff + dns->rtcp_len - 1] = (len & 0xff);
|
||||
if (len & 3) {
|
||||
u32 pad = 4 - (len & 3);
|
||||
|
||||
memset(dns->p + coff + dns->rtcp_len + len, 0, pad);
|
||||
len += pad;
|
||||
}
|
||||
wlen = len / 4;
|
||||
wlen += 3;
|
||||
dns->p[coff + dns->rtcp_len - 14] = (wlen >> 8);
|
||||
dns->p[coff + dns->rtcp_len - 13] = (wlen & 0xff);
|
||||
ddbcpyto(dev, off, dns->p, sizeof(dns->p));
|
||||
ddbwritel(dev, (dns->rtcp_udplen + len) |
|
||||
((STREAM_PACKET_OFF(dns->nr) + coff) << 16),
|
||||
STREAM_RTCP_PACKET(dns->nr));
|
||||
ddbwritel(dev, ddbreadl(dev, STREAM_CONTROL(dns->nr)) | 0x10,
|
||||
STREAM_CONTROL(dns->nr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 set_nsbuf(struct dvb_ns_params *p, u8 *buf,
|
||||
u32 *udplen, int rtcp, int vlan)
|
||||
{
|
||||
u32 c = 0;
|
||||
u16 pcs;
|
||||
u16 sport, dport;
|
||||
|
||||
sport = rtcp ? p->sport2 : p->sport;
|
||||
dport = rtcp ? p->dport2 : p->dport;
|
||||
|
||||
/* MAC header */
|
||||
memcpy(buf + c, p->dmac, 6);
|
||||
memcpy(buf + c + 6, p->smac, 6);
|
||||
c += 12;
|
||||
if (vlan) {
|
||||
buf[c + 0] = 0x81;
|
||||
buf[c + 1] = 0x00;
|
||||
buf[c + 2] = ((p->qos & 7) << 5) | ((p->vlan & 0xf00) >> 8);
|
||||
buf[c + 3] = p->vlan & 0xff;
|
||||
c += 4;
|
||||
}
|
||||
buf[c + 0] = 0x08;
|
||||
buf[c + 1] = 0x00;
|
||||
c += 2;
|
||||
|
||||
/* IP header */
|
||||
if (p->flags & DVB_NS_IPV6) {
|
||||
u8 ip6head[8] = { 0x65, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x11, 0x00, };
|
||||
memcpy(buf + c, ip6head, sizeof(ip6head));
|
||||
buf[c + 7] = p->ttl;
|
||||
memcpy(buf + c + 8, p->sip, 16);
|
||||
memcpy(buf + c + 24, p->dip, 16);
|
||||
c += 40;
|
||||
|
||||
/* UDP */
|
||||
buf[c + 0] = sport >> 8;
|
||||
buf[c + 1] = sport & 0xff;
|
||||
buf[c + 2] = dport >> 8;
|
||||
buf[c + 3] = dport & 0xff;
|
||||
buf[c + 4] = 0; /* length */
|
||||
buf[c + 5] = 0;
|
||||
pcs = calc_pcs16(p, p->flags & DVB_NS_IPV6);
|
||||
buf[c + 6] = pcs >> 8;
|
||||
buf[c + 7] = pcs & 0xff;
|
||||
c += 8;
|
||||
*udplen = 8;
|
||||
|
||||
} else {
|
||||
u8 ip4head[12] = { 0x45, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x40, 0x00, 0x40, 0x11, 0x00, 0x00 };
|
||||
|
||||
memcpy(buf + c, ip4head, sizeof(ip4head));
|
||||
buf[c + 8] = p->ttl;
|
||||
memcpy(buf + c + 12, p->sip, 4);
|
||||
memcpy(buf + c + 16, p->dip, 4);
|
||||
c += 20;
|
||||
|
||||
/* UDP */
|
||||
buf[c + 0] = sport >> 8;
|
||||
buf[c + 1] = sport & 0xff;
|
||||
buf[c + 2] = dport >> 8;
|
||||
buf[c + 3] = dport & 0xff;
|
||||
buf[c + 4] = 0; /* length */
|
||||
buf[c + 5] = 0;
|
||||
pcs = calc_pcs(p);
|
||||
buf[c + 6] = pcs >> 8;
|
||||
buf[c + 7] = pcs & 0xff;
|
||||
c += 8;
|
||||
*udplen = 8;
|
||||
}
|
||||
|
||||
if (rtcp) {
|
||||
memcpy(buf + c, rtcp_head, sizeof(rtcp_head));
|
||||
memcpy(buf + c + 4, p->ssrc, 4);
|
||||
memcpy(buf + c + 32, p->ssrc, 4);
|
||||
memcpy(buf + c + 48, p->ssrc, 4);
|
||||
c += sizeof(rtcp_head);
|
||||
*udplen += sizeof(rtcp_head);
|
||||
} else if (p->flags & DVB_NS_RTP) {
|
||||
memcpy(buf + c, rtp_head, sizeof(rtp_head));
|
||||
memcpy(buf + c + 8, p->ssrc, 4);
|
||||
c += sizeof(rtp_head);
|
||||
*udplen += sizeof(rtp_head);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static int ns_set_ts_packets(struct dvbnss *nss, u8 *buf, u32 len)
|
||||
{
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
u32 off = STREAM_PACKET_ADR(dns->nr);
|
||||
|
||||
if (nss->params.flags & DVB_NS_RTCP)
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(dns->p + dns->ts_offset, buf, len))
|
||||
return -EFAULT;
|
||||
ddbcpyto(dev, off, dns->p, sizeof(dns->p));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ns_insert_ts_packets(struct dvbnss *nss, u8 count)
|
||||
{
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
u32 value = count;
|
||||
|
||||
if (nss->params.flags & DVB_NS_RTCP)
|
||||
return -EINVAL;
|
||||
|
||||
if (count < 1 || count > 2)
|
||||
return -EINVAL;
|
||||
|
||||
ddbwritel(dev, value, STREAM_INSERT_PACKET(dns->nr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ns_set_net(struct dvbnss *nss)
|
||||
{
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
struct dvb_ns_params *p = &nss->params;
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
u32 off = STREAM_PACKET_ADR(dns->nr);
|
||||
u32 coff = 96;
|
||||
|
||||
dns->ts_offset = set_nsbuf(p, dns->p, &dns->udplen, 0, dev->vlan);
|
||||
if (nss->params.flags & DVB_NS_RTCP)
|
||||
dns->rtcp_len = set_nsbuf(p, dns->p + coff,
|
||||
&dns->rtcp_udplen, 1, dev->vlan);
|
||||
ddbcpyto(dev, off, dns->p, sizeof(dns->p));
|
||||
ddbwritel(dev, dns->udplen | (STREAM_PACKET_OFF(dns->nr) << 16),
|
||||
STREAM_RTP_PACKET(dns->nr));
|
||||
ddbwritel(dev, dns->rtcp_udplen |
|
||||
((STREAM_PACKET_OFF(dns->nr) + coff) << 16),
|
||||
STREAM_RTCP_PACKET(dns->nr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ns_start(struct dvbnss *nss)
|
||||
{
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
u32 reg = 0x8003;
|
||||
|
||||
if (nss->params.flags & DVB_NS_RTCP)
|
||||
reg |= 0x10;
|
||||
if (nss->params.flags & DVB_NS_RTP_TO)
|
||||
reg |= 0x20;
|
||||
if (nss->params.flags & DVB_NS_RTP)
|
||||
reg |= 0x40;
|
||||
if (nss->params.flags & DVB_NS_IPV6)
|
||||
reg |= 0x80;
|
||||
if (dns->fe != input)
|
||||
ddb_dvb_ns_input_start(dns->fe);
|
||||
ddb_dvb_ns_input_start(input);
|
||||
printk("ns start ns %u, fe %u link %u\n", dns->nr, dns->fe->nr, dns->fe->port->lnr);
|
||||
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
|
||||
STREAM_CONTROL(dns->nr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ns_stop(struct dvbnss *nss)
|
||||
{
|
||||
struct ddb_ns *dns = (struct ddb_ns *) nss->priv;
|
||||
struct dvb_netstream *ns = nss->ns;
|
||||
struct ddb_input *input = ns->priv;
|
||||
struct ddb *dev = input->port->dev;
|
||||
|
||||
ddbwritel(dev, 0x00, STREAM_CONTROL(dns->nr));
|
||||
ddb_dvb_ns_input_stop(input);
|
||||
if (dns->fe != input)
|
||||
ddb_dvb_ns_input_stop(dns->fe);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int netstream_init(struct ddb_input *input)
|
||||
{
|
||||
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
|
||||
struct dvb_adapter *adap = dvb->adap;
|
||||
struct dvb_netstream *ns = &dvb->dvbns;
|
||||
struct ddb *dev = input->port->dev;
|
||||
int i, res;
|
||||
|
||||
ddbmemset(dev, STREAM_PIDS(input->nr), 0x00, 0x400);
|
||||
for (i = 0; i < dev->ns_num; i++)
|
||||
dev->ns[i].nr = i;
|
||||
ns->priv = input;
|
||||
ns->set_net = ns_set_net;
|
||||
ns->set_rtcp_msg = ns_set_rtcp_msg;
|
||||
ns->set_ts_packets = ns_set_ts_packets;
|
||||
ns->insert_ts_packets = ns_insert_ts_packets;
|
||||
ns->set_pid = ns_set_pid;
|
||||
ns->set_pids = ns_set_pids;
|
||||
ns->set_ci = ns_set_ci;
|
||||
ns->start = ns_start;
|
||||
ns->stop = ns_stop;
|
||||
ns->alloc = ns_alloc;
|
||||
ns->free = ns_free;
|
||||
res = dvb_netstream_init(adap, ns);
|
||||
return res;
|
||||
}
|
435
ddbridge/ddbridge-regs.h
Normal file
435
ddbridge/ddbridge-regs.h
Normal file
@@ -0,0 +1,435 @@
|
||||
/*
|
||||
* ddbridge-regs.h: Digital Devices PCIe bridge driver
|
||||
*
|
||||
* Copyright (C) 2010-2015 Digital Devices GmbH
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/* Register Definitions */
|
||||
|
||||
#define CUR_REGISTERMAP_VERSION 0x10003
|
||||
#define CUR_REGISTERMAP_VERSION_CI 0x10000
|
||||
#define CUR_REGISTERMAP_VERSION_MOD 0x10000
|
||||
|
||||
#define HARDWARE_VERSION 0x00
|
||||
#define REGISTERMAP_VERSION 0x04
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* SPI Controller */
|
||||
|
||||
#define SPI_CONTROL 0x10
|
||||
#define SPI_DATA 0x14
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* GPIO */
|
||||
|
||||
#define GPIO_OUTPUT 0x20
|
||||
#define GPIO_INPUT 0x24
|
||||
#define GPIO_DIRECTION 0x28
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* MDIO */
|
||||
|
||||
#define MDIO_CTRL 0x20
|
||||
#define MDIO_ADR 0x24
|
||||
#define MDIO_REG 0x28
|
||||
#define MDIO_VAL 0x2C
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define BOARD_CONTROL 0x30
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
/* Interrupt controller
|
||||
How many MSI's are available depends on HW (Min 2 max 8)
|
||||
How many are usable also depends on Host platform
|
||||
*/
|
||||
|
||||
#define INTERRUPT_BASE (0x40)
|
||||
|
||||
#define INTERRUPT_ENABLE (INTERRUPT_BASE + 0x00)
|
||||
#define MSI0_ENABLE (INTERRUPT_BASE + 0x00)
|
||||
#define MSI1_ENABLE (INTERRUPT_BASE + 0x04)
|
||||
#define MSI2_ENABLE (INTERRUPT_BASE + 0x08)
|
||||
#define MSI3_ENABLE (INTERRUPT_BASE + 0x0C)
|
||||
#define MSI4_ENABLE (INTERRUPT_BASE + 0x10)
|
||||
#define MSI5_ENABLE (INTERRUPT_BASE + 0x14)
|
||||
#define MSI6_ENABLE (INTERRUPT_BASE + 0x18)
|
||||
#define MSI7_ENABLE (INTERRUPT_BASE + 0x1C)
|
||||
|
||||
#define INTERRUPT_STATUS (INTERRUPT_BASE + 0x20)
|
||||
#define INTERRUPT_ACK (INTERRUPT_BASE + 0x20)
|
||||
|
||||
#define INTMASK_CLOCKGEN (0x00000001)
|
||||
#define INTMASK_TEMPMON (0x00000002)
|
||||
|
||||
#define INTMASK_I2C1 (0x00000001)
|
||||
#define INTMASK_I2C2 (0x00000002)
|
||||
#define INTMASK_I2C3 (0x00000004)
|
||||
#define INTMASK_I2C4 (0x00000008)
|
||||
|
||||
#define INTMASK_CIRQ1 (0x00000010)
|
||||
#define INTMASK_CIRQ2 (0x00000020)
|
||||
#define INTMASK_CIRQ3 (0x00000040)
|
||||
#define INTMASK_CIRQ4 (0x00000080)
|
||||
|
||||
#define INTMASK_TSINPUT1 (0x00000100)
|
||||
#define INTMASK_TSINPUT2 (0x00000200)
|
||||
#define INTMASK_TSINPUT3 (0x00000400)
|
||||
#define INTMASK_TSINPUT4 (0x00000800)
|
||||
#define INTMASK_TSINPUT5 (0x00001000)
|
||||
#define INTMASK_TSINPUT6 (0x00002000)
|
||||
#define INTMASK_TSINPUT7 (0x00004000)
|
||||
#define INTMASK_TSINPUT8 (0x00008000)
|
||||
|
||||
#define INTMASK_TSOUTPUT1 (0x00010000)
|
||||
#define INTMASK_TSOUTPUT2 (0x00020000)
|
||||
#define INTMASK_TSOUTPUT3 (0x00040000)
|
||||
#define INTMASK_TSOUTPUT4 (0x00080000)
|
||||
|
||||
|
||||
|
||||
/* Modulator registers */
|
||||
|
||||
/* Clock Generator ( Sil598 @ 0xAA I2c ) */
|
||||
#define CLOCKGEN_BASE (0x80)
|
||||
#define CLOCKGEN_CONTROL (CLOCKGEN_BASE + 0x00)
|
||||
#define CLOCKGEN_INDEX (CLOCKGEN_BASE + 0x04)
|
||||
#define CLOCKGEN_WRITEDATA (CLOCKGEN_BASE + 0x08)
|
||||
#define CLOCKGEN_READDATA (CLOCKGEN_BASE + 0x0C)
|
||||
|
||||
/* DAC ( AD9781/AD9783 SPI ) */
|
||||
#define DAC_BASE (0x090)
|
||||
#define DAC_CONTROL (DAC_BASE)
|
||||
#define DAC_WRITE_DATA (DAC_BASE+4)
|
||||
#define DAC_READ_DATA (DAC_BASE+8)
|
||||
|
||||
#define DAC_CONTROL_INSTRUCTION_REG (0xFF)
|
||||
#define DAC_CONTROL_STARTIO (0x100)
|
||||
#define DAC_CONTROL_RESET (0x200)
|
||||
|
||||
/* Temperature Monitor ( 2x LM75A @ 0x90,0x92 I2c ) */
|
||||
#define TEMPMON_BASE (0xA0)
|
||||
#define TEMPMON_CONTROL (TEMPMON_BASE + 0x00)
|
||||
/* SHORT Temperature in <20>C x 256 */
|
||||
#define TEMPMON_CORE (TEMPMON_BASE + 0x04)
|
||||
#define TEMPMON_SENSOR1 (TEMPMON_BASE + 0x08)
|
||||
#define TEMPMON_SENSOR2 (TEMPMON_BASE + 0x0C)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* I2C Master Controller */
|
||||
|
||||
#define I2C_BASE (0x80) /* Byte offset */
|
||||
|
||||
#define I2C_COMMAND (0x00)
|
||||
#define I2C_TIMING (0x04)
|
||||
#define I2C_TASKLENGTH (0x08) /* High read, low write */
|
||||
#define I2C_TASKADDRESS (0x0C) /* High read, low write */
|
||||
#define I2C_MONITOR (0x1C)
|
||||
|
||||
|
||||
#define I2C_SPEED_666 (0x02010202)
|
||||
#define I2C_SPEED_400 (0x04030404)
|
||||
#define I2C_SPEED_200 (0x09080909)
|
||||
#define I2C_SPEED_154 (0x0C0B0C0C)
|
||||
#define I2C_SPEED_100 (0x13121313)
|
||||
#define I2C_SPEED_77 (0x19181919)
|
||||
#define I2C_SPEED_50 (0x27262727)
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* DMA Controller */
|
||||
|
||||
#define DMA_BASE_WRITE (0x100)
|
||||
#define DMA_BASE_READ (0x140)
|
||||
|
||||
#define DMA_CONTROL (0x00)
|
||||
#define DMA_ERROR (0x04)
|
||||
|
||||
#define DMA_DIAG_CONTROL (0x1C)
|
||||
#define DMA_DIAG_PACKETCOUNTER_LOW (0x20)
|
||||
#define DMA_DIAG_PACKETCOUNTER_HIGH (0x24)
|
||||
#define DMA_DIAG_TIMECOUNTER_LOW (0x28)
|
||||
#define DMA_DIAG_TIMECOUNTER_HIGH (0x2C)
|
||||
#define DMA_DIAG_RECHECKCOUNTER (0x30)
|
||||
#define DMA_DIAG_WAITTIMEOUTINIT (0x34)
|
||||
#define DMA_DIAG_WAITOVERFLOWCOUNTER (0x38)
|
||||
#define DMA_DIAG_WAITCOUNTER (0x3C)
|
||||
|
||||
#define TS_INPUT_BASE (0x200)
|
||||
#define TS_INPUT_CONTROL(i) (TS_INPUT_BASE + (i) * 0x10 + 0x00)
|
||||
#define TS_INPUT_CONTROL2(i) (TS_INPUT_BASE + (i) * 0x10 + 0x04)
|
||||
|
||||
#define TS_OUTPUT_BASE (0x280)
|
||||
#define TS_OUTPUT_CONTROL(i) (TS_OUTPUT_BASE + (i) * 0x10 + 0x00)
|
||||
#define TS_OUTPUT_CONTROL2(i) (TS_OUTPUT_BASE + (i) * 0x10 + 0x04)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* DMA Buffer */
|
||||
|
||||
#define DMA_BUFFER_BASE (0x300)
|
||||
|
||||
#define DMA_BUFFER_CONTROL(i) (DMA_BUFFER_BASE + (i) * 0x10 + 0x00)
|
||||
#define DMA_BUFFER_ACK(i) (DMA_BUFFER_BASE + (i) * 0x10 + 0x04)
|
||||
#define DMA_BUFFER_CURRENT(i) (DMA_BUFFER_BASE + (i) * 0x10 + 0x08)
|
||||
#define DMA_BUFFER_SIZE(i) (DMA_BUFFER_BASE + (i) * 0x10 + 0x0c)
|
||||
|
||||
#define DMA_BASE_ADDRESS_TABLE (0x2000)
|
||||
#define DMA_BASE_ADDRESS_TABLE_ENTRIES (512)
|
||||
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
#define LNB_BASE (0x400)
|
||||
#define LNB_CONTROL(i) (LNB_BASE + (i) * 0x20 + 0x00)
|
||||
#define LNB_CMD (7ULL << 0)
|
||||
#define LNB_CMD_NOP 0
|
||||
#define LNB_CMD_INIT 1
|
||||
#define LNB_CMD_STATUS 2
|
||||
#define LNB_CMD_LOW 3
|
||||
#define LNB_CMD_HIGH 4
|
||||
#define LNB_CMD_OFF 5
|
||||
#define LNB_CMD_DISEQC 6
|
||||
#define LNB_CMD_UNI 7
|
||||
|
||||
#define LNB_BUSY (1ULL << 4)
|
||||
#define LNB_TONE (1ULL << 15)
|
||||
|
||||
#define LNB_STATUS(i) (LNB_BASE + (i) * 0x20 + 0x04)
|
||||
#define LNB_VOLTAGE(i) (LNB_BASE + (i) * 0x20 + 0x08)
|
||||
#define LNB_CONFIG(i) (LNB_BASE + (i) * 0x20 + 0x0c)
|
||||
#define LNB_BUF_LEVEL(i) (LNB_BASE + (i) * 0x20 + 0x10)
|
||||
#define LNB_BUF_WRITE(i) (LNB_BASE + (i) * 0x20 + 0x14)
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
/* 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)
|
||||
|
||||
#define VCO1_BASE (0xC0)
|
||||
#define VCO1_CONTROL (VCO1_BASE + 0x00)
|
||||
#define VCO1_DATA (VCO1_BASE + 0x04) /* 24 Bit */
|
||||
/* 1 = Trigger write, resets when done */
|
||||
#define VCO1_CONTROL_WRITE (0x00000001)
|
||||
/* 0 = Put VCO into power down */
|
||||
#define VCO1_CONTROL_CE (0x00000002)
|
||||
/* Muxout from VCO (usually = Lock) */
|
||||
#define VCO1_CONTROL_MUXOUT (0x00000004)
|
||||
|
||||
#define VCO2_BASE (0xC8)
|
||||
#define VCO2_CONTROL (VCO2_BASE + 0x00)
|
||||
#define VCO2_DATA (VCO2_BASE + 0x04) /* 24 Bit */
|
||||
/* 1 = Trigger write, resets when done */
|
||||
#define VCO2_CONTROL_WRITE (0x00000001)
|
||||
/* 0 = Put VCO into power down */
|
||||
#define VCO2_CONTROL_CE (0x00000002)
|
||||
/* Muxout from VCO (usually = Lock) */
|
||||
#define VCO2_CONTROL_MUXOUT (0x00000004)
|
||||
|
||||
#define VCO3_BASE (0xD0)
|
||||
#define VCO3_CONTROL (VCO3_BASE + 0x00)
|
||||
#define VCO3_DATA (VCO3_BASE + 0x04) /* 32 Bit */
|
||||
/* 1 = Trigger write, resets when done */
|
||||
#define VCO3_CONTROL_WRITE (0x00000001)
|
||||
/* 0 = Put VCO into power down */
|
||||
#define VCO3_CONTROL_CE (0x00000002)
|
||||
/* Muxout from VCO (usually = Lock) */
|
||||
#define VCO3_CONTROL_MUXOUT (0x00000004)
|
||||
|
||||
#define RF_ATTENUATOR (0xD8)
|
||||
/* 0x00 = 0 dB
|
||||
0x01 = 1 dB
|
||||
...
|
||||
0x1F = 31 dB
|
||||
*/
|
||||
|
||||
#define RF_POWER (0xE0)
|
||||
#define RF_POWER_BASE (0xE0)
|
||||
#define RF_POWER_CONTROL (RF_POWER_BASE + 0x00)
|
||||
#define RF_POWER_DATA (RF_POWER_BASE + 0x04)
|
||||
|
||||
#define RF_POWER_CONTROL_START (0x00000001)
|
||||
#define RF_POWER_CONTROL_DONE (0x00000002)
|
||||
#define RF_POWER_CONTROL_VALIDMASK (0x00000700)
|
||||
#define RF_POWER_CONTROL_VALID (0x00000500)
|
||||
|
||||
|
||||
/* --------------------------------------------------------------------------
|
||||
Output control
|
||||
*/
|
||||
|
||||
#define IQOUTPUT_BASE (0x240)
|
||||
#define IQOUTPUT_CONTROL (IQOUTPUT_BASE + 0x00)
|
||||
#define IQOUTPUT_CONTROL2 (IQOUTPUT_BASE + 0x04)
|
||||
#define IQOUTPUT_PEAK_DETECTOR (IQOUTPUT_BASE + 0x08)
|
||||
#define IQOUTPUT_POSTSCALER (IQOUTPUT_BASE + 0x0C)
|
||||
#define IQOUTPUT_PRESCALER (IQOUTPUT_BASE + 0x10)
|
||||
|
||||
#define IQOUTPUT_EQUALIZER_0 (IQOUTPUT_BASE + 0x14)
|
||||
#define IQOUTPUT_EQUALIZER_1 (IQOUTPUT_BASE + 0x18)
|
||||
#define IQOUTPUT_EQUALIZER_2 (IQOUTPUT_BASE + 0x1C)
|
||||
#define IQOUTPUT_EQUALIZER_3 (IQOUTPUT_BASE + 0x20)
|
||||
#define IQOUTPUT_EQUALIZER_4 (IQOUTPUT_BASE + 0x24)
|
||||
#define IQOUTPUT_EQUALIZER_5 (IQOUTPUT_BASE + 0x28)
|
||||
#define IQOUTPUT_EQUALIZER_6 (IQOUTPUT_BASE + 0x2C)
|
||||
#define IQOUTPUT_EQUALIZER_7 (IQOUTPUT_BASE + 0x30)
|
||||
#define IQOUTPUT_EQUALIZER_8 (IQOUTPUT_BASE + 0x34)
|
||||
#define IQOUTPUT_EQUALIZER_9 (IQOUTPUT_BASE + 0x38)
|
||||
#define IQOUTPUT_EQUALIZER_10 (IQOUTPUT_BASE + 0x3C)
|
||||
|
||||
#define IQOUTPUT_EQUALIZER(i) (IQOUTPUT_EQUALIZER_0 + (i) * 4)
|
||||
|
||||
#define IQOUTPUT_CONTROL_RESET (0x00000001)
|
||||
#define IQOUTPUT_CONTROL_ENABLE (0x00000002)
|
||||
#define IQOUTPUT_CONTROL_RESET_PEAK (0x00000004)
|
||||
#define IQOUTPUT_CONTROL_ENABLE_PEAK (0x00000008)
|
||||
#define IQOUTPUT_CONTROL_BYPASS_EQUALIZER (0x00000010)
|
||||
|
||||
|
||||
/* Modulator Base */
|
||||
|
||||
#define MODULATOR_BASE (0x200)
|
||||
#define MODULATOR_CONTROL (MODULATOR_BASE)
|
||||
#define MODULATOR_IQTABLE_END (MODULATOR_BASE+4)
|
||||
#define MODULATOR_IQTABLE_INDEX (MODULATOR_BASE+8)
|
||||
#define MODULATOR_IQTABLE_DATA (MODULATOR_BASE+12)
|
||||
|
||||
#define MODULATOR_IQTABLE_INDEX_CHANNEL_MASK (0x000F0000)
|
||||
#define MODULATOR_IQTABLE_INDEX_IQ_MASK (0x00008000)
|
||||
#define MODULATOR_IQTABLE_INDEX_ADDRESS_MASK (0x000007FF)
|
||||
#define MODULATOR_IQTABLE_INDEX_SEL_I (0x00000000)
|
||||
#define MODULATOR_IQTABLE_INDEX_SEL_Q (MODULATOR_IQTABLE_INDEX_IQ_MASK)
|
||||
#define MODULATOR_IQTABLE_SIZE (2048)
|
||||
|
||||
|
||||
/* Modulator Channels */
|
||||
|
||||
#define CHANNEL_BASE (0x400)
|
||||
#define CHANNEL_CONTROL(i) (CHANNEL_BASE + (i) * 64 + 0x00)
|
||||
#define CHANNEL_SETTINGS(i) (CHANNEL_BASE + (i) * 64 + 0x04)
|
||||
#define CHANNEL_RATE_INCR(i) (CHANNEL_BASE + (i) * 64 + 0x0C)
|
||||
#define CHANNEL_PCR_ADJUST_OUTL(i) (CHANNEL_BASE + (i) * 64 + 0x10)
|
||||
#define CHANNEL_PCR_ADJUST_OUTH(i) (CHANNEL_BASE + (i) * 64 + 0x14)
|
||||
#define CHANNEL_PCR_ADJUST_INL(i) (CHANNEL_BASE + (i) * 64 + 0x18)
|
||||
#define CHANNEL_PCR_ADJUST_INH(i) (CHANNEL_BASE + (i) * 64 + 0x1C)
|
||||
#define CHANNEL_PCR_ADJUST_ACCUL(i) (CHANNEL_BASE + (i) * 64 + 0x20)
|
||||
#define CHANNEL_PCR_ADJUST_ACCUH(i) (CHANNEL_BASE + (i) * 64 + 0x24)
|
||||
#define CHANNEL_PKT_COUNT_OUT(i) (CHANNEL_BASE + (i) * 64 + 0x28)
|
||||
#define CHANNEL_PKT_COUNT_IN(i) (CHANNEL_BASE + (i) * 64 + 0x2C)
|
||||
|
||||
#define CHANNEL_CONTROL_RESET (0x00000001)
|
||||
#define CHANNEL_CONTROL_ENABLE_DVB (0x00000002)
|
||||
#define CHANNEL_CONTROL_ENABLE_IQ (0x00000004)
|
||||
#define CHANNEL_CONTROL_ENABLE_SOURCE (0x00000008)
|
||||
#define CHANNEL_CONTROL_ENABLE_PCRADJUST (0x00000010)
|
||||
#define CHANNEL_CONTROL_FREEZE_STATUS (0x00000100)
|
||||
|
||||
#define CHANNEL_CONTROL_RESET_ERROR (0x00010000)
|
||||
#define CHANNEL_CONTROL_BUSY (0x01000000)
|
||||
#define CHANNEL_CONTROL_ERROR_SYNC (0x20000000)
|
||||
#define CHANNEL_CONTROL_ERROR_UNDERRUN (0x40000000)
|
||||
#define CHANNEL_CONTROL_ERROR_FATAL (0x80000000)
|
||||
|
||||
#define CHANNEL_SETTINGS_QAM_MASK (0x00000007)
|
||||
#define CHANNEL_SETTINGS_QAM16 (0x00000000)
|
||||
#define CHANNEL_SETTINGS_QAM32 (0x00000001)
|
||||
#define CHANNEL_SETTINGS_QAM64 (0x00000002)
|
||||
#define CHANNEL_SETTINGS_QAM128 (0x00000003)
|
||||
#define CHANNEL_SETTINGS_QAM256 (0x00000004)
|
||||
|
||||
|
||||
/* OCTONET */
|
||||
|
||||
#define ETHER_BASE (0x100)
|
||||
#define ETHER_CONTROL (ETHER_BASE + 0x00)
|
||||
#define ETHER_LENGTH (ETHER_BASE + 0x04)
|
||||
|
||||
#define RTP_MASTER_BASE (0x120)
|
||||
#define RTP_MASTER_CONTROL (RTP_MASTER_BASE + 0x00)
|
||||
#define RTP_RTCP_INTERRUPT (RTP_MASTER_BASE + 0x04)
|
||||
#define RTP_MASTER_RTCP_SETTINGS (RTP_MASTER_BASE + 0x0c)
|
||||
|
||||
#define STREAM_BASE (0x400)
|
||||
#define STREAM_CONTROL(i) (STREAM_BASE + (i) * 0x20 + 0x00)
|
||||
#define STREAM_RTP_PACKET(i) (STREAM_BASE + (i) * 0x20 + 0x04)
|
||||
#define STREAM_RTCP_PACKET(i) (STREAM_BASE + (i) * 0x20 + 0x08)
|
||||
#define STREAM_RTP_SETTINGS(i) (STREAM_BASE + (i) * 0x20 + 0x0c)
|
||||
#define STREAM_INSERT_PACKET(i) (STREAM_BASE + (i) * 0x20 + 0x10)
|
||||
|
||||
#define STREAM_PACKET_OFF(i) ((i) * 0x200)
|
||||
#define STREAM_PACKET_ADR(i) (0x2000 + (STREAM_PACKET_OFF(i)))
|
||||
|
||||
#define STREAM_PIDS(i) (0x4000 + (i) * 0x400)
|
||||
|
||||
#define TS_CAPTURE_BASE (0x0140)
|
||||
#define TS_CAPTURE_CONTROL (TS_CAPTURE_BASE + 0x00)
|
||||
#define TS_CAPTURE_PID (TS_CAPTURE_BASE + 0x04)
|
||||
#define TS_CAPTURE_RECEIVED (TS_CAPTURE_BASE + 0x08)
|
||||
#define TS_CAPTURE_TIMEOUT (TS_CAPTURE_BASE + 0x0c)
|
||||
#define TS_CAPTURE_TABLESECTION (TS_CAPTURE_BASE + 0x10)
|
||||
|
||||
#define TS_CAPTURE_MEMORY (0x7000)
|
||||
|
||||
#define PID_FILTER_BASE (0x800)
|
||||
#define PID_FILTER_SYSTEM_PIDS(i) (PID_FILTER_BASE + (i) * 0x20)
|
||||
#define PID_FILTER_PID(i, j) (PID_FILTER_BASE + (i) * 0x20 + (j) * 4)
|
||||
|
||||
|
||||
|
533
ddbridge/ddbridge.c
Normal file
533
ddbridge/ddbridge.c
Normal file
@@ -0,0 +1,533 @@
|
||||
/*
|
||||
* ddbridge.c: Digital Devices PCIe bridge driver
|
||||
*
|
||||
* Copyright (C) 2010-2015 Digital Devices GmbH
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
/*#define DDB_ALT_DMA*/
|
||||
#define DDB_USE_WORK
|
||||
/*#define DDB_TEST_THREADED*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-regs.h"
|
||||
|
||||
static struct workqueue_struct *ddb_wq;
|
||||
|
||||
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");
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
static int msi = 1;
|
||||
module_param(msi, int, 0444);
|
||||
MODULE_PARM_DESC(msi,
|
||||
" Control MSI interrupts: 0-disable, 1-enable (default)");
|
||||
#endif
|
||||
|
||||
#include "ddbridge-core.c"
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static void ddb_unmap(struct ddb *dev)
|
||||
{
|
||||
if (dev->regs)
|
||||
iounmap(dev->regs);
|
||||
vfree(dev);
|
||||
}
|
||||
|
||||
|
||||
static void __devexit ddb_remove(struct pci_dev *pdev)
|
||||
{
|
||||
struct ddb *dev = (struct ddb *) pci_get_drvdata(pdev);
|
||||
|
||||
ddb_nsd_detach(dev);
|
||||
ddb_ports_detach(dev);
|
||||
ddb_i2c_release(dev);
|
||||
|
||||
if (dev->link[0].info->ns_num)
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
ddbwritel(dev, 0, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0, MSI1_ENABLE);
|
||||
if (dev->msi == 2)
|
||||
free_irq(dev->pdev->irq + 1, dev);
|
||||
free_irq(dev->pdev->irq, dev);
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
#endif
|
||||
ddb_ports_release(dev);
|
||||
ddb_buffers_free(dev);
|
||||
ddb_device_destroy(dev);
|
||||
|
||||
ddb_unmap(dev);
|
||||
pci_set_drvdata(pdev, 0);
|
||||
pci_disable_device(pdev);
|
||||
}
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
|
||||
#define __devinit
|
||||
#define __devinitdata
|
||||
#endif
|
||||
|
||||
static int __devinit ddb_probe(struct pci_dev *pdev,
|
||||
const struct pci_device_id *id)
|
||||
{
|
||||
struct ddb *dev;
|
||||
int stat = 0;
|
||||
int irq_flag = IRQF_SHARED;
|
||||
|
||||
if (pci_enable_device(pdev) < 0)
|
||||
return -ENODEV;
|
||||
|
||||
dev = vzalloc(sizeof(struct ddb));
|
||||
if (dev == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
mutex_init(&dev->mutex);
|
||||
dev->has_dma = 1;
|
||||
dev->pdev = pdev;
|
||||
dev->dev = &pdev->dev;
|
||||
pci_set_drvdata(pdev, dev);
|
||||
|
||||
dev->ids.vendor = id->vendor;
|
||||
dev->ids.device = id->device;
|
||||
dev->ids.subvendor = id->subvendor;
|
||||
dev->ids.subdevice = id->subdevice;
|
||||
|
||||
dev->link[0].dev = dev;
|
||||
dev->link[0].info = (struct ddb_info *) id->driver_data;
|
||||
pr_info("DDBridge driver detected: %s\n", dev->link[0].info->name);
|
||||
|
||||
dev->regs_len = pci_resource_len(dev->pdev, 0);
|
||||
dev->regs = ioremap(pci_resource_start(dev->pdev, 0),
|
||||
pci_resource_len(dev->pdev, 0));
|
||||
|
||||
if (!dev->regs) {
|
||||
pr_err("DDBridge: not enough memory for register map\n");
|
||||
stat = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
if (ddbreadl(dev, 0) == 0xffffffff) {
|
||||
pr_err("DDBridge: cannot read registers\n");
|
||||
stat = -ENODEV;
|
||||
goto fail;
|
||||
}
|
||||
|
||||
dev->ids.hwid = ddbreadl(dev, 0);
|
||||
dev->ids.regmapid = ddbreadl(dev, 4);
|
||||
|
||||
pr_info("DDBridge: HW %08x REGMAP %08x\n",
|
||||
dev->ids.hwid, dev->ids.regmapid);
|
||||
|
||||
if (dev->link[0].info->ns_num) {
|
||||
int i;
|
||||
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
for (i = 0; i < 16; i++)
|
||||
ddbwritel(dev, 0x00, TS_OUTPUT_CONTROL(i));
|
||||
usleep_range(5000, 6000);
|
||||
}
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI2_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI3_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI4_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI5_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI6_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI7_ENABLE);
|
||||
|
||||
#ifdef CONFIG_PCI_MSI
|
||||
if (msi && pci_msi_enabled()) {
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 15, 0))
|
||||
stat = pci_enable_msi_range(dev->pdev, 1, 2);
|
||||
if (stat >= 1) {
|
||||
dev->msi = stat;
|
||||
pr_info("DDBridge: using %d MSI interrupt(s)\n", dev->msi);
|
||||
irq_flag = 0;
|
||||
} else
|
||||
pr_info("DDBridge: MSI not available.\n");
|
||||
|
||||
#else
|
||||
stat = pci_enable_msi_block(dev->pdev, 2);
|
||||
if (stat == 0) {
|
||||
dev->msi = 1;
|
||||
pr_info("DDBridge: using 2 MSI interrupts\n");
|
||||
}
|
||||
if (stat == 1)
|
||||
stat = pci_enable_msi(dev->pdev);
|
||||
if (stat < 0) {
|
||||
pr_info("DDBridge: MSI not available.\n");
|
||||
} else {
|
||||
irq_flag = 0;
|
||||
dev->msi++;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
if (dev->msi == 2) {
|
||||
stat = request_irq(dev->pdev->irq, irq_handler0,
|
||||
irq_flag, "ddbridge", (void *) dev);
|
||||
if (stat < 0)
|
||||
goto fail0;
|
||||
stat = request_irq(dev->pdev->irq + 1, irq_handler1,
|
||||
irq_flag, "ddbridge", (void *) dev);
|
||||
if (stat < 0) {
|
||||
free_irq(dev->pdev->irq, dev);
|
||||
goto fail0;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
#ifdef DDB_TEST_THREADED
|
||||
stat = request_threaded_irq(dev->pdev->irq, irq_handler,
|
||||
irq_thread,
|
||||
irq_flag,
|
||||
"ddbridge", (void *) dev);
|
||||
#else
|
||||
stat = request_irq(dev->pdev->irq, irq_handler,
|
||||
irq_flag, "ddbridge", (void *) dev);
|
||||
#endif
|
||||
if (stat < 0)
|
||||
goto fail0;
|
||||
}
|
||||
ddbwritel(dev, 0, DMA_BASE_READ);
|
||||
if (dev->link[0].info->type != DDB_MOD)
|
||||
ddbwritel(dev, 0, DMA_BASE_WRITE);
|
||||
|
||||
if (dev->link[0].info->type == DDB_MOD) {
|
||||
if (ddbreadl(dev, 0x1c) == 4)
|
||||
dev->link[0].info->port_num = 4;
|
||||
}
|
||||
|
||||
/*ddbwritel(dev, 0xffffffff, INTERRUPT_ACK);*/
|
||||
if (dev->msi == 2) {
|
||||
ddbwritel(dev, 0x0fffff00, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0x0000000f, MSI1_ENABLE);
|
||||
} else {
|
||||
ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0x00000000, MSI1_ENABLE);
|
||||
}
|
||||
if (ddb_init(dev) == 0)
|
||||
return 0;
|
||||
|
||||
ddbwritel(dev, 0, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0, MSI1_ENABLE);
|
||||
free_irq(dev->pdev->irq, dev);
|
||||
if (dev->msi == 2)
|
||||
free_irq(dev->pdev->irq + 1, dev);
|
||||
fail0:
|
||||
pr_err("fail0\n");
|
||||
if (dev->msi)
|
||||
pci_disable_msi(dev->pdev);
|
||||
fail:
|
||||
pr_err("fail\n");
|
||||
|
||||
ddb_unmap(dev);
|
||||
pci_set_drvdata(pdev, 0);
|
||||
pci_disable_device(pdev);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
static struct ddb_regset octopus_i2c = {
|
||||
.base = 0x80,
|
||||
.num = 0x04,
|
||||
.size = 0x20,
|
||||
};
|
||||
|
||||
static struct ddb_regset octopus_i2c_buf = {
|
||||
.base = 0x1000,
|
||||
.num = 0x04,
|
||||
.size = 0x200,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
|
||||
static struct ddb_regmap octopus_map = {
|
||||
.i2c = &octopus_i2c,
|
||||
.i2c_buf = &octopus_i2c_buf,
|
||||
};
|
||||
|
||||
static struct ddb_regmap octopus_net_map = {
|
||||
.i2c = &octopus_i2c,
|
||||
.i2c_buf = &octopus_i2c_buf,
|
||||
};
|
||||
|
||||
static struct ddb_regmap octopus_mod_map = {
|
||||
};
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static struct ddb_info ddb_none = {
|
||||
.type = DDB_NONE,
|
||||
.name = "unknown Digital Devices PCIe card, install newer driver",
|
||||
.regmap = &octopus_map,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopus = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopusv3 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus V3 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopus_le = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus LE DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 2,
|
||||
.i2c_mask = 0x03,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopus_oem = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus OEM",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.led_num = 1,
|
||||
.fan_num = 1,
|
||||
.temp_num = 1,
|
||||
.temp_bus = 0,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopus_mini = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Octopus Mini",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_v6 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine S2 V6 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x07,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_v6_5 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine S2 V6.5 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_v7 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine S2 V7 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 2,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_ctv7 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices Cine CT V7 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.board_control = 3,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_satixS2v3 = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Mystique SaTiX-S2 V3 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x07,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_ci = {
|
||||
.type = DDB_OCTOPUS_CI,
|
||||
.name = "Digital Devices Octopus CI",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x03,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_cis = {
|
||||
.type = DDB_OCTOPUS_CI,
|
||||
.name = "Digital Devices Octopus CI single",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x01,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_ci_s2_pro = {
|
||||
.type = DDB_OCTOPUS_CI,
|
||||
.name = "Digital Devices Octopus CI S2 Pro",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x01,
|
||||
.board_control = 3,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_dvbct = {
|
||||
.type = DDB_OCTOPUS,
|
||||
.name = "Digital Devices DVBCT V6.1 DVB adapter",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 3,
|
||||
.i2c_mask = 0x07,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
static struct ddb_info ddb_s2_48 = {
|
||||
.type = DDB_OCTOPUS_MAX,
|
||||
.name = "Digital Devices MAX S8 4/8",
|
||||
.regmap = &octopus_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x01,
|
||||
.board_control = 1,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_mod = {
|
||||
.type = DDB_MOD,
|
||||
.name = "Digital Devices DVB-C modulator",
|
||||
.regmap = &octopus_mod_map,
|
||||
.port_num = 10,
|
||||
.temp_num = 1,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octopus_net = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet network DVB adapter",
|
||||
.regmap = &octopus_net_map,
|
||||
.port_num = 10,
|
||||
.i2c_mask = 0x3ff,
|
||||
.ns_num = 12,
|
||||
.mdio_num = 1,
|
||||
};
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
#define DDVID 0xdd01 /* Digital Devices Vendor ID */
|
||||
|
||||
#define DDB_ID(_vend, _dev, _subvend, _subdev, _driverdata) { \
|
||||
.vendor = _vend, .device = _dev, \
|
||||
.subvendor = _subvend, .subdevice = _subdev, \
|
||||
.driver_data = (unsigned long)&_driverdata }
|
||||
|
||||
static const struct pci_device_id ddb_id_tbl[] __devinitconst = {
|
||||
DDB_ID(DDVID, 0x0002, DDVID, 0x0001, ddb_octopus),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0001, ddb_octopus),
|
||||
DDB_ID(DDVID, 0x0005, DDVID, 0x0004, ddb_octopusv3),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0002, ddb_octopus_le),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0003, ddb_octopus_oem),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0010, ddb_octopus_mini),
|
||||
DDB_ID(DDVID, 0x0005, DDVID, 0x0011, ddb_octopus_mini),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0020, ddb_v6),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0021, ddb_v6_5),
|
||||
DDB_ID(DDVID, 0x0006, DDVID, 0x0022, ddb_v7),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0x0030, ddb_dvbct),
|
||||
DDB_ID(DDVID, 0x0003, DDVID, 0xdb03, ddb_satixS2v3),
|
||||
DDB_ID(DDVID, 0x0006, DDVID, 0x0031, ddb_ctv7),
|
||||
DDB_ID(DDVID, 0x0006, DDVID, 0x0032, ddb_ctv7),
|
||||
DDB_ID(DDVID, 0x0006, DDVID, 0x0033, ddb_ctv7),
|
||||
DDB_ID(DDVID, 0x0007, DDVID, 0x0023, ddb_s2_48),
|
||||
DDB_ID(DDVID, 0x0011, DDVID, 0x0040, ddb_ci),
|
||||
DDB_ID(DDVID, 0x0011, DDVID, 0x0041, ddb_cis),
|
||||
DDB_ID(DDVID, 0x0012, DDVID, 0x0042, ddb_ci),
|
||||
DDB_ID(DDVID, 0x0013, DDVID, 0x0043, ddb_ci_s2_pro),
|
||||
DDB_ID(DDVID, 0x0201, DDVID, 0x0001, ddb_mod),
|
||||
DDB_ID(DDVID, 0x0201, DDVID, 0x0002, ddb_mod),
|
||||
DDB_ID(DDVID, 0x0320, PCI_ANY_ID, PCI_ANY_ID, ddb_octopus_net),
|
||||
/* in case sub-ids got deleted in flash */
|
||||
DDB_ID(DDVID, 0x0003, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0005, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0006, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0007, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0011, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0013, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0201, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
DDB_ID(DDVID, 0x0320, PCI_ANY_ID, PCI_ANY_ID, ddb_none),
|
||||
{0}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(pci, ddb_id_tbl);
|
||||
|
||||
static struct pci_driver ddb_pci_driver = {
|
||||
.name = "ddbridge",
|
||||
.id_table = ddb_id_tbl,
|
||||
.probe = ddb_probe,
|
||||
.remove = ddb_remove,
|
||||
};
|
||||
|
||||
static __init int module_init_ddbridge(void)
|
||||
{
|
||||
int stat = -1;
|
||||
|
||||
pr_info("Digital Devices PCIE bridge driver "
|
||||
DDBRIDGE_VERSION
|
||||
", Copyright (C) 2010-15 Digital Devices GmbH\n");
|
||||
if (ddb_class_create() < 0)
|
||||
return -1;
|
||||
ddb_wq = create_workqueue("ddbridge");
|
||||
if (ddb_wq == NULL)
|
||||
goto exit1;
|
||||
stat = pci_register_driver(&ddb_pci_driver);
|
||||
if (stat < 0)
|
||||
goto exit2;
|
||||
return stat;
|
||||
exit2:
|
||||
destroy_workqueue(ddb_wq);
|
||||
exit1:
|
||||
ddb_class_destroy();
|
||||
return stat;
|
||||
}
|
||||
|
||||
static __exit void module_exit_ddbridge(void)
|
||||
{
|
||||
pci_unregister_driver(&ddb_pci_driver);
|
||||
destroy_workqueue(ddb_wq);
|
||||
ddb_class_destroy();
|
||||
}
|
||||
|
||||
module_init(module_init_ddbridge);
|
||||
module_exit(module_exit_ddbridge);
|
||||
|
||||
MODULE_DESCRIPTION("Digital Devices PCIe Bridge");
|
||||
MODULE_AUTHOR("Ralph and Marcus Metzler, Metzler Brothers Systementwicklung GbR");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DDBRIDGE_VERSION);
|
711
ddbridge/ddbridge.h
Normal file
711
ddbridge/ddbridge.h
Normal file
@@ -0,0 +1,711 @@
|
||||
/*
|
||||
* ddbridge.h: Digital Devices PCIe bridge driver
|
||||
*
|
||||
* Copyright (C) 2010-2015 Digital Devices GmbH
|
||||
* Ralph Metzler <rmetzler@digitaldevices.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#ifndef _DDBRIDGE_H_
|
||||
#define _DDBRIDGE_H_
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(3, 8, 0))
|
||||
#define __devexit
|
||||
#define __devinit
|
||||
#define __devinitconst
|
||||
#endif
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/poll.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/pci.h>
|
||||
//#include <linux/pci_ids.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/swab.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/clk.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/gpio.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/dvb/ca.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "dvb_netstream.h"
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb_ringbuffer.h"
|
||||
#include "dvb_ca_en50221.h"
|
||||
#include "dvb_net.h"
|
||||
|
||||
#include "tda18271c2dd.h"
|
||||
#include "stv6110x.h"
|
||||
#include "stv090x.h"
|
||||
#include "lnbh24.h"
|
||||
#include "drxk.h"
|
||||
#include "stv0367dd.h"
|
||||
#include "tda18212dd.h"
|
||||
#include "cxd2843.h"
|
||||
#include "cxd2099.h"
|
||||
#include "stv0910.h"
|
||||
#include "stv6111.h"
|
||||
#include "lnbh25.h"
|
||||
#include "mxl5xx.h"
|
||||
|
||||
#define DDB_MAX_I2C 16
|
||||
#define DDB_MAX_PORT 16
|
||||
#define DDB_MAX_INPUT 44
|
||||
#define DDB_MAX_OUTPUT 10
|
||||
#define DDB_MAX_LINK 4
|
||||
#define DDB_LINK_SHIFT 28
|
||||
|
||||
#define DDB_LINK_TAG(_x) (_x << DDB_LINK_SHIFT)
|
||||
|
||||
struct ddb_regset {
|
||||
u32 base;
|
||||
u32 num;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct ddb_ports {
|
||||
u32 base;
|
||||
u32 num;
|
||||
u32 size;
|
||||
};
|
||||
|
||||
struct ddb_regmap {
|
||||
struct ddb_ports *bc;
|
||||
struct ddb_regset *i2c;
|
||||
struct ddb_regset *i2c_buf;
|
||||
struct ddb_regset *dma;
|
||||
struct ddb_regset *dma_buf;
|
||||
struct ddb_regset *input;
|
||||
struct ddb_regset *output;
|
||||
struct ddb_regset *channel;
|
||||
struct ddb_regset *ci;
|
||||
struct ddb_regset *pid_filter;
|
||||
struct ddb_regset *ns;
|
||||
struct ddb_regset *gtl;
|
||||
};
|
||||
|
||||
struct ddb_ids {
|
||||
u16 vendor;
|
||||
u16 device;
|
||||
u16 subvendor;
|
||||
u16 subdevice;
|
||||
|
||||
u32 hwid;
|
||||
u32 regmapid;
|
||||
u32 devid;
|
||||
u32 mac;
|
||||
};
|
||||
|
||||
struct ddb_info {
|
||||
int type;
|
||||
#define DDB_NONE 0
|
||||
#define DDB_OCTOPUS 1
|
||||
#define DDB_OCTOPUS_CI 2
|
||||
#define DDB_MOD 3
|
||||
#define DDB_OCTONET 4
|
||||
#define DDB_OCTOPUS_MAX 5
|
||||
char *name;
|
||||
u32 i2c_mask;
|
||||
u8 port_num;
|
||||
u8 led_num;
|
||||
u8 fan_num;
|
||||
u8 temp_num;
|
||||
u8 temp_bus;
|
||||
u8 board_control;
|
||||
u8 ns_num;
|
||||
u8 mdio_num;
|
||||
u8 con_clock;
|
||||
struct ddb_regmap *regmap;
|
||||
};
|
||||
|
||||
/* DMA_SIZE MUST be smaller than 256k and
|
||||
MUST be divisible by 188 and 128 !!! */
|
||||
|
||||
#define DMA_MAX_BUFS 32 /* hardware table limit */
|
||||
|
||||
#define INPUT_DMA_BUFS 8
|
||||
#define INPUT_DMA_SIZE (128*47*21)
|
||||
#define INPUT_DMA_IRQ_DIV 1
|
||||
|
||||
#define OUTPUT_DMA_BUFS 8
|
||||
#define OUTPUT_DMA_SIZE (128*47*21)
|
||||
#define OUTPUT_DMA_IRQ_DIV 1
|
||||
|
||||
struct ddb;
|
||||
struct ddb_port;
|
||||
|
||||
struct ddb_dma {
|
||||
void *io;
|
||||
u32 nr;
|
||||
dma_addr_t pbuf[DMA_MAX_BUFS];
|
||||
u8 *vbuf[DMA_MAX_BUFS];
|
||||
u32 num;
|
||||
u32 size;
|
||||
u32 div;
|
||||
u32 bufreg;
|
||||
|
||||
#ifdef DDB_USE_WORK
|
||||
struct work_struct work;
|
||||
#else
|
||||
struct tasklet_struct tasklet;
|
||||
#endif
|
||||
spinlock_t lock;
|
||||
wait_queue_head_t wq;
|
||||
int running;
|
||||
u32 stat;
|
||||
u32 ctrl;
|
||||
u32 cbuf;
|
||||
u32 coff;
|
||||
};
|
||||
|
||||
struct ddb_dvb {
|
||||
struct dvb_adapter *adap;
|
||||
int adap_registered;
|
||||
struct dvb_device *dev;
|
||||
struct dvb_frontend *fe;
|
||||
struct dvb_frontend *fe2;
|
||||
struct dmxdev dmxdev;
|
||||
struct dvb_demux demux;
|
||||
struct dvb_net dvbnet;
|
||||
struct dvb_netstream dvbns;
|
||||
struct dmx_frontend hw_frontend;
|
||||
struct dmx_frontend mem_frontend;
|
||||
int users;
|
||||
u32 attached;
|
||||
u8 input;
|
||||
|
||||
fe_sec_tone_mode_t tone;
|
||||
fe_sec_voltage_t voltage;
|
||||
|
||||
int (*i2c_gate_ctrl)(struct dvb_frontend *, int);
|
||||
int (*set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
|
||||
int (*set_input)(struct dvb_frontend *fe, int input);
|
||||
int (*diseqc_send_master_cmd)(struct dvb_frontend* fe, struct dvb_diseqc_master_cmd* cmd);
|
||||
};
|
||||
|
||||
struct ddb_ci {
|
||||
struct dvb_ca_en50221 en;
|
||||
struct ddb_port *port;
|
||||
u32 nr;
|
||||
struct mutex lock;
|
||||
};
|
||||
|
||||
struct ddb_io {
|
||||
struct ddb_port *port;
|
||||
u32 nr;
|
||||
struct ddb_dma *dma;
|
||||
struct ddb_io *redo;
|
||||
struct ddb_io *redi;
|
||||
};
|
||||
|
||||
#define ddb_output ddb_io
|
||||
#define ddb_input ddb_io
|
||||
|
||||
struct ddb_i2c {
|
||||
struct ddb *dev;
|
||||
u32 nr;
|
||||
u32 regs;
|
||||
u32 link;
|
||||
struct i2c_adapter adap;
|
||||
u32 rbuf;
|
||||
u32 wbuf;
|
||||
u32 bsize;
|
||||
struct completion completion;
|
||||
};
|
||||
|
||||
struct ddb_port {
|
||||
struct ddb *dev;
|
||||
u32 nr;
|
||||
u32 pnr;
|
||||
u32 regs;
|
||||
u32 lnr;
|
||||
struct ddb_i2c *i2c;
|
||||
struct mutex i2c_gate_lock;
|
||||
u32 class;
|
||||
#define DDB_PORT_NONE 0
|
||||
#define DDB_PORT_CI 1
|
||||
#define DDB_PORT_TUNER 2
|
||||
#define DDB_PORT_LOOP 3
|
||||
#define DDB_PORT_MOD 4
|
||||
char *name;
|
||||
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 3
|
||||
#define DDB_TUNER_DVBCT_ST 4
|
||||
#define DDB_CI_INTERNAL 5
|
||||
#define DDB_CI_EXTERNAL_SONY 6
|
||||
#define DDB_TUNER_DVBCT2_SONY_P 7
|
||||
#define DDB_TUNER_DVBC2T2_SONY_P 8
|
||||
#define DDB_TUNER_ISDBT_SONY_P 9
|
||||
#define DDB_TUNER_DVBS_STV0910_P 10
|
||||
#define DDB_TUNER_MXL5XX 11
|
||||
#define DDB_CI_EXTERNAL_XO2 12
|
||||
#define DDB_CI_EXTERNAL_XO2_B 13
|
||||
|
||||
#define DDB_TUNER_XO2 16
|
||||
#define DDB_TUNER_DVBS_STV0910 16
|
||||
#define DDB_TUNER_DVBCT2_SONY 17
|
||||
#define DDB_TUNER_ISDBT_SONY 18
|
||||
#define DDB_TUNER_DVBC2T2_SONY 19
|
||||
#define DDB_TUNER_ATSC_ST 20
|
||||
#define DDB_TUNER_DVBC2T2_ST 21
|
||||
|
||||
struct ddb_input *input[2];
|
||||
struct ddb_output *output;
|
||||
struct dvb_ca_en50221 *en;
|
||||
struct ddb_dvb dvb[2];
|
||||
u32 gap;
|
||||
u32 obr;
|
||||
u8 creg;
|
||||
};
|
||||
|
||||
struct mod_base {
|
||||
u32 frequency;
|
||||
u32 flat_start;
|
||||
u32 flat_end;
|
||||
};
|
||||
|
||||
struct mod_state {
|
||||
u32 modulation;
|
||||
u64 obitrate;
|
||||
u64 ibitrate;
|
||||
u32 pcr_correction;
|
||||
|
||||
u32 rate_inc;
|
||||
u32 Control;
|
||||
u32 State;
|
||||
u32 StateCounter;
|
||||
s32 LastPCRAdjust;
|
||||
s32 PCRAdjustSum;
|
||||
s32 InPacketsSum;
|
||||
s32 OutPacketsSum;
|
||||
s64 PCRIncrement;
|
||||
s64 PCRDecrement;
|
||||
s32 PCRRunningCorr;
|
||||
u32 OutOverflowPacketCount;
|
||||
u32 InOverflowPacketCount;
|
||||
u32 LastOutPacketCount;
|
||||
u32 LastInPacketCount;
|
||||
u64 LastOutPackets;
|
||||
u64 LastInPackets;
|
||||
u32 MinInputPackets;
|
||||
};
|
||||
|
||||
#define CM_STARTUP_DELAY 2
|
||||
#define CM_AVERAGE 20
|
||||
#define CM_GAIN 10
|
||||
|
||||
#define HW_LSB_SHIFT 12
|
||||
#define HW_LSB_MASK 0x1000
|
||||
|
||||
#define CM_IDLE 0
|
||||
#define CM_STARTUP 1
|
||||
#define CM_ADJUST 2
|
||||
|
||||
#define TS_CAPTURE_LEN (4096)
|
||||
|
||||
/* net streaming hardware block */
|
||||
|
||||
#define DDB_NS_MAX 15
|
||||
|
||||
struct ddb_ns {
|
||||
struct ddb_input *input;
|
||||
int nr;
|
||||
struct ddb_input *fe;
|
||||
u32 rtcp_udplen;
|
||||
u32 rtcp_len;
|
||||
u32 ts_offset;
|
||||
u32 udplen;
|
||||
u8 p[512];
|
||||
};
|
||||
|
||||
struct ddb_lnb {
|
||||
struct mutex lock;
|
||||
u32 tone;
|
||||
fe_sec_voltage_t oldvoltage[4];
|
||||
u32 voltage[4];
|
||||
u32 voltages;
|
||||
u32 fmode;
|
||||
u32 setmode;
|
||||
};
|
||||
|
||||
struct ddb_link {
|
||||
struct ddb *dev;
|
||||
struct ddb_info *info;
|
||||
u32 nr;
|
||||
u32 regs;
|
||||
spinlock_t lock;
|
||||
struct mutex flash_mutex;
|
||||
struct ddb_lnb lnb;
|
||||
struct tasklet_struct tasklet;
|
||||
};
|
||||
|
||||
struct ddb {
|
||||
struct pci_dev *pdev;
|
||||
struct platform_device *pfdev;
|
||||
struct device *dev;
|
||||
struct ddb_ids ids;
|
||||
|
||||
int msi;
|
||||
struct workqueue_struct *wq;
|
||||
u32 has_dma;
|
||||
u32 has_ns;
|
||||
|
||||
struct ddb_link link[DDB_MAX_LINK];
|
||||
unsigned char *regs;
|
||||
u32 regs_len;
|
||||
u32 port_num;
|
||||
struct ddb_port port[DDB_MAX_PORT];
|
||||
u32 i2c_num;
|
||||
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];
|
||||
|
||||
void (*handler[128])(unsigned long);
|
||||
unsigned long handler_data[128];
|
||||
|
||||
struct device *ddb_dev;
|
||||
u32 ddb_dev_users;
|
||||
u32 nr;
|
||||
u8 iobuf[1028];
|
||||
|
||||
u8 leds;
|
||||
u32 ts_irq;
|
||||
u32 i2c_irq;
|
||||
|
||||
int ns_num;
|
||||
struct ddb_ns ns[DDB_NS_MAX];
|
||||
int vlan;
|
||||
struct mutex mutex;
|
||||
|
||||
struct dvb_device *nsd_dev;
|
||||
u8 tsbuf[TS_CAPTURE_LEN];
|
||||
|
||||
struct mod_base mod_base;
|
||||
struct mod_state mod[10];
|
||||
};
|
||||
|
||||
static inline void ddbwriteb(struct ddb *dev, u32 val, u32 adr)
|
||||
{
|
||||
writeb(val, (char *) (dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static inline u32 ddbreadb(struct ddb *dev, u32 adr)
|
||||
{
|
||||
return readb((char *) (dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static inline void ddbwritel0(struct ddb_link *link, u32 val, u32 adr)
|
||||
{
|
||||
writel(val, (char *) (link->dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static inline u32 ddbreadl0(struct ddb_link *link, u32 adr)
|
||||
{
|
||||
return readl((char *) (link->dev->regs + (adr)));
|
||||
}
|
||||
|
||||
#if 0
|
||||
static inline void gtlw(struct ddb_link *link)
|
||||
{
|
||||
u32 count = 0;
|
||||
static u32 max = 0;
|
||||
|
||||
while (1 & ddbreadl0(link, link->regs + 0x10)) {
|
||||
if (++count == 1024) {
|
||||
printk("LTO\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (count > max) {
|
||||
max = count;
|
||||
printk("TO=%u\n", max);
|
||||
}
|
||||
if (ddbreadl0(link, link->regs + 0x10) & 0x8000)
|
||||
printk("link error\n");
|
||||
}
|
||||
#else
|
||||
static inline void gtlw(struct ddb_link *link)
|
||||
{
|
||||
while (1 & ddbreadl0(link, link->regs + 0x10));
|
||||
}
|
||||
#endif
|
||||
|
||||
static u32 ddblreadl(struct ddb_link *link, u32 adr)
|
||||
{
|
||||
if (unlikely(link->nr)) {
|
||||
unsigned long flags;
|
||||
u32 val;
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddbwritel0(link, adr & 0xfffc, link->regs + 0x14);
|
||||
ddbwritel0(link, 3, link->regs + 0x10);
|
||||
gtlw(link);
|
||||
val = ddbreadl0(link, link->regs + 0x1c);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return val;
|
||||
}
|
||||
return readl((char *) (link->dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static void ddblwritel(struct ddb_link *link, u32 val, u32 adr)
|
||||
{
|
||||
if (unlikely(link->nr)) {
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddbwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
|
||||
ddbwritel0(link, val, link->regs + 0x18);
|
||||
ddbwritel0(link, 1, link->regs + 0x10);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return;
|
||||
}
|
||||
writel(val, (char *) (link->dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static u32 ddbreadl(struct ddb *dev, u32 adr)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000)) {
|
||||
unsigned long flags;
|
||||
u32 val, l = (adr >> DDB_LINK_SHIFT);
|
||||
struct ddb_link *link = &dev->link[l];
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddbwritel0(link, adr & 0xfffc, link->regs + 0x14);
|
||||
ddbwritel0(link, 3, link->regs + 0x10);
|
||||
gtlw(link);
|
||||
val = ddbreadl0(link, link->regs + 0x1c);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return val;
|
||||
}
|
||||
return readl((char *) (dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static void ddbwritel(struct ddb *dev, u32 val, u32 adr)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000)) {
|
||||
unsigned long flags;
|
||||
u32 l = (adr >> DDB_LINK_SHIFT);
|
||||
struct ddb_link *link = &dev->link[l];
|
||||
|
||||
spin_lock_irqsave(&link->lock, flags);
|
||||
gtlw(link);
|
||||
ddbwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);
|
||||
ddbwritel0(link, val, link->regs + 0x18);
|
||||
ddbwritel0(link, 1, link->regs + 0x10);
|
||||
spin_unlock_irqrestore(&link->lock, flags);
|
||||
return;
|
||||
}
|
||||
writel(val, (char *) (dev->regs + (adr)));
|
||||
}
|
||||
|
||||
static void gtlcpyto(struct ddb *dev, u32 adr, const u8 *buf,
|
||||
unsigned int count)
|
||||
{
|
||||
u32 val = 0, p = adr;
|
||||
u32 aa = p & 3;
|
||||
|
||||
if (aa) {
|
||||
while (p & 3 && count) {
|
||||
val >>= 8;
|
||||
val |= *buf << 24;
|
||||
p++;
|
||||
buf++;
|
||||
count--;
|
||||
}
|
||||
ddbwritel(dev, val, adr);
|
||||
}
|
||||
while (count >= 4) {
|
||||
val = buf[0] | (buf[1] << 8) | (buf[2] << 16) | (buf[3] << 24);
|
||||
ddbwritel(dev, val, p);
|
||||
p += 4;
|
||||
buf += 4;
|
||||
count -= 4;
|
||||
}
|
||||
if (count) {
|
||||
val = buf[0];
|
||||
if (count > 1)
|
||||
val |= buf[1] << 8;
|
||||
if (count > 2)
|
||||
val |= buf[2] << 16;
|
||||
ddbwritel(dev, val, p);
|
||||
}
|
||||
}
|
||||
|
||||
static void gtlcpyfrom(struct ddb *dev, u8 *buf, u32 adr, long count)
|
||||
{
|
||||
u32 val = 0, p = adr;
|
||||
u32 a = p & 3;
|
||||
|
||||
if (a) {
|
||||
val = ddbreadl(dev, p) >> (8 * a);
|
||||
while (p & 3 && count) {
|
||||
*buf = val & 0xff;
|
||||
val >>= 8;
|
||||
p++;
|
||||
buf++;
|
||||
count--;
|
||||
}
|
||||
}
|
||||
while (count >= 4) {
|
||||
val = ddbreadl(dev, p);
|
||||
buf[0] = val & 0xff;
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
buf[2] = (val >> 16) & 0xff;
|
||||
buf[3] = (val >> 24) & 0xff;
|
||||
p += 4;
|
||||
buf += 4;
|
||||
count -= 4;
|
||||
}
|
||||
if (count) {
|
||||
val = ddbreadl(dev, p);
|
||||
buf[0] = val & 0xff;
|
||||
if (count > 1)
|
||||
buf[1] = (val >> 8) & 0xff;
|
||||
if (count > 2)
|
||||
buf[2] = (val >> 16) & 0xff;
|
||||
}
|
||||
}
|
||||
|
||||
static void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000))
|
||||
return gtlcpyto(dev, adr, src, count);
|
||||
return memcpy_toio((char *) (dev->regs + adr), src, count);
|
||||
}
|
||||
|
||||
static void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count)
|
||||
{
|
||||
if (unlikely(adr & 0xf0000000))
|
||||
return gtlcpyfrom(dev, dst, adr, count);
|
||||
return memcpy_fromio(dst, (char *) (dev->regs + adr), count);
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
#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))
|
||||
#endif
|
||||
|
||||
#define ddbmemset(_dev, _adr, _val, _count) \
|
||||
memset_io((char *) (_dev->regs + (_adr)), (_val), (_count))
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
/****************************************************************************/
|
||||
|
||||
#define dd_uint8 u8
|
||||
#define dd_uint16 u16
|
||||
#define dd_int16 s16
|
||||
#define dd_uint32 u32
|
||||
#define dd_int32 s32
|
||||
#define dd_uint64 u64
|
||||
#define dd_int64 s64
|
||||
|
||||
#define DDMOD_FLASH_START 0x1000
|
||||
|
||||
struct DDMOD_FLASH_DS {
|
||||
dd_uint32 Symbolrate; /* kSymbols/s */
|
||||
dd_uint32 DACFrequency; /* kHz */
|
||||
dd_uint16 FrequencyResolution; /* kHz */
|
||||
dd_uint16 IQTableLength;
|
||||
dd_uint16 FrequencyFactor;
|
||||
dd_int16 PhaseCorr; /* TBD */
|
||||
dd_uint32 Control2;
|
||||
dd_uint16 PostScaleI;
|
||||
dd_uint16 PostScaleQ;
|
||||
dd_uint16 PreScale;
|
||||
dd_int16 EQTap[11];
|
||||
dd_uint16 FlatStart;
|
||||
dd_uint16 FlatEnd;
|
||||
dd_uint32 FlashOffsetPrecalculatedIQTables; /* 0 = none */
|
||||
dd_uint8 Reserved[28];
|
||||
|
||||
};
|
||||
|
||||
struct DDMOD_FLASH {
|
||||
dd_uint32 Magic;
|
||||
dd_uint16 Version;
|
||||
dd_uint16 DataSets;
|
||||
|
||||
dd_uint16 VCORefFrequency; /* MHz */
|
||||
dd_uint16 VCO1Frequency; /* MHz */
|
||||
dd_uint16 VCO2Frequency; /* MHz */
|
||||
|
||||
dd_uint16 DACAux1; /* TBD */
|
||||
dd_uint16 DACAux2; /* TBD */
|
||||
|
||||
dd_uint8 Reserved1[238];
|
||||
|
||||
struct DDMOD_FLASH_DS DataSet[1];
|
||||
};
|
||||
|
||||
#define DDMOD_FLASH_MAGIC 0x5F564d5F
|
||||
|
||||
|
||||
int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg);
|
||||
int ddbridge_mod_init(struct ddb *dev);
|
||||
void ddbridge_mod_output_stop(struct ddb_output *output);
|
||||
void ddbridge_mod_output_start(struct ddb_output *output);
|
||||
void ddbridge_mod_rate_handler(unsigned long data);
|
||||
|
||||
|
||||
int ddbridge_flashread(struct ddb *dev, u32 link, u8 *buf, u32 addr, u32 len);
|
||||
|
||||
#define DDBRIDGE_VERSION "0.9.19"
|
||||
|
||||
#endif
|
260
ddbridge/octonet.c
Normal file
260
ddbridge/octonet.c
Normal file
@@ -0,0 +1,260 @@
|
||||
/*
|
||||
* octonet.c: Digital Devices network tuner driver
|
||||
*
|
||||
* Copyright (C) 2012-15 Digital Devices GmbH
|
||||
* Marcus Metzler <mocm@metzlerbros.de>
|
||||
* Ralph Metzler <rjkm@metzlerbros.de>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* version 2 only, as published by the Free Software Foundation.
|
||||
*
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
|
||||
* 02110-1301, USA
|
||||
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
|
||||
*/
|
||||
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-regs.h"
|
||||
#include <asm-generic/pci-dma-compat.h>
|
||||
|
||||
static int adapter_alloc = 3;
|
||||
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");
|
||||
|
||||
#include "ddbridge-core.c"
|
||||
|
||||
static struct ddb_regset octopus_i2c = {
|
||||
.base = 0x80,
|
||||
.num = 0x04,
|
||||
.size = 0x20,
|
||||
};
|
||||
|
||||
static struct ddb_regset octopus_i2c_buf = {
|
||||
.base = 0x1000,
|
||||
.num = 0x04,
|
||||
.size = 0x200,
|
||||
};
|
||||
|
||||
static struct ddb_regmap octopus_net_map = {
|
||||
.i2c = &octopus_i2c,
|
||||
.i2c_buf = &octopus_i2c_buf,
|
||||
};
|
||||
|
||||
static struct ddb_regset octopus_gtl = {
|
||||
.base = 0x180,
|
||||
.num = 0x01,
|
||||
.size = 0x20,
|
||||
};
|
||||
|
||||
static struct ddb_regmap octopus_net_gtl = {
|
||||
.i2c = &octopus_i2c,
|
||||
.i2c_buf = &octopus_i2c_buf,
|
||||
.gtl = &octopus_gtl,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octonet = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet network DVB adapter",
|
||||
.regmap = &octopus_net_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.ns_num = 12,
|
||||
.mdio_num = 1,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octonet_jse = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet network DVB adapter JSE",
|
||||
.regmap = &octopus_net_map,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x0f,
|
||||
.ns_num = 15,
|
||||
.mdio_num = 1,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octonet_gtl = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet GTL",
|
||||
.regmap = &octopus_net_gtl,
|
||||
.port_num = 4,
|
||||
.i2c_mask = 0x05,
|
||||
.ns_num = 12,
|
||||
.mdio_num = 1,
|
||||
.con_clock = 1,
|
||||
};
|
||||
|
||||
static struct ddb_info ddb_octonet_tbd = {
|
||||
.type = DDB_OCTONET,
|
||||
.name = "Digital Devices OctopusNet",
|
||||
.regmap = &octopus_net_map,
|
||||
};
|
||||
|
||||
static void octonet_unmap(struct ddb *dev)
|
||||
{
|
||||
if (dev->regs)
|
||||
iounmap(dev->regs);
|
||||
vfree(dev);
|
||||
}
|
||||
|
||||
static int __exit octonet_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ddb *dev;
|
||||
|
||||
dev = platform_get_drvdata(pdev);
|
||||
|
||||
ddb_nsd_detach(dev);
|
||||
ddb_ports_detach(dev);
|
||||
ddb_i2c_release(dev);
|
||||
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
ddbwritel(dev, 0, INTERRUPT_ENABLE);
|
||||
free_irq(platform_get_irq(dev->pfdev, 0), dev);
|
||||
|
||||
ddb_ports_release(dev);
|
||||
ddb_device_destroy(dev);
|
||||
octonet_unmap(dev);
|
||||
platform_set_drvdata(pdev, 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __init octonet_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct ddb *dev;
|
||||
struct resource *regs;
|
||||
int irq;
|
||||
int i;
|
||||
|
||||
dev = vzalloc(sizeof(struct ddb));
|
||||
if (!dev)
|
||||
return -ENOMEM;
|
||||
platform_set_drvdata(pdev, dev);
|
||||
dev->dev = &pdev->dev;
|
||||
dev->pfdev = pdev;
|
||||
|
||||
mutex_init(&dev->mutex);
|
||||
regs = platform_get_resource(dev->pfdev, IORESOURCE_MEM, 0);
|
||||
if (!regs)
|
||||
return -ENXIO;
|
||||
dev->regs_len = (regs->end - regs->start) + 1;
|
||||
dev_info(dev->dev, "regs_start=%08x regs_len=%08x\n",
|
||||
(u32) regs->start, (u32) dev->regs_len);
|
||||
dev->regs = ioremap(regs->start, dev->regs_len);
|
||||
|
||||
if (!dev->regs) {
|
||||
dev_err(dev->dev, "ioremap failed\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dev->ids.hwid = ddbreadl(dev, 0);
|
||||
dev->ids.regmapid = ddbreadl(dev, 4);
|
||||
dev->ids.devid = ddbreadl(dev, 8);
|
||||
dev->ids.mac = ddbreadl(dev, 12);
|
||||
|
||||
dev->ids.vendor = dev->ids.devid & 0xffff;
|
||||
dev->ids.device = dev->ids.devid >> 16;
|
||||
dev->ids.subvendor = dev->ids.devid & 0xffff;
|
||||
dev->ids.subdevice = dev->ids.devid >> 16;
|
||||
|
||||
dev->link[0].dev = dev;
|
||||
if (dev->ids.devid == 0x0300dd01)
|
||||
dev->link[0].info = &ddb_octonet;
|
||||
else if (dev->ids.devid == 0x0301dd01)
|
||||
dev->link[0].info = &ddb_octonet_jse;
|
||||
else if (dev->ids.devid == 0x0307dd01)
|
||||
dev->link[0].info = &ddb_octonet_gtl;
|
||||
else
|
||||
dev->link[0].info = &ddb_octonet_tbd;
|
||||
|
||||
pr_info("HW %08x REGMAP %08x\n", dev->ids.hwid, dev->ids.regmapid);
|
||||
pr_info("MAC %08x DEVID %08x\n", dev->ids.mac, dev->ids.devid);
|
||||
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
ddbwritel(dev, 0x00000000, INTERRUPT_ENABLE);
|
||||
ddbwritel(dev, 0xffffffff, INTERRUPT_STATUS);
|
||||
for (i = 0; i < 16; i++)
|
||||
ddbwritel(dev, 0x00, TS_OUTPUT_CONTROL(i));
|
||||
usleep_range(5000, 6000);
|
||||
|
||||
irq = platform_get_irq(dev->pfdev, 0);
|
||||
if (irq < 0)
|
||||
goto fail;
|
||||
if (request_irq(irq, irq_handler,
|
||||
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
|
||||
"octonet-dvb", (void *) dev) < 0)
|
||||
goto fail;
|
||||
ddbwritel(dev, 0x0fffff0f, INTERRUPT_ENABLE);
|
||||
|
||||
if (ddb_init(dev) == 0)
|
||||
return 0;
|
||||
|
||||
fail:
|
||||
dev_err(dev->dev, "fail\n");
|
||||
ddbwritel(dev, 0, ETHER_CONTROL);
|
||||
ddbwritel(dev, 0, INTERRUPT_ENABLE);
|
||||
octonet_unmap(dev);
|
||||
platform_set_drvdata(pdev, 0);
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_OF
|
||||
static const struct of_device_id octonet_dt_ids[] = {
|
||||
{ .compatible = "digitaldevices,octonet-dvb" },
|
||||
{ /* sentinel */ }
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, octonet_dt_ids);
|
||||
#endif
|
||||
|
||||
static struct platform_driver octonet_driver = {
|
||||
.remove = __exit_p(octonet_remove),
|
||||
.probe = octonet_probe,
|
||||
.driver = {
|
||||
.name = "octonet-dvb",
|
||||
.owner = THIS_MODULE,
|
||||
#ifdef CONFIG_OF
|
||||
.of_match_table = of_match_ptr(octonet_dt_ids),
|
||||
#endif
|
||||
},
|
||||
};
|
||||
|
||||
static __init int init_octonet(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
pr_info("Digital Devices OctopusNet driver " DDBRIDGE_VERSION
|
||||
", Copyright (C) 2010-14 Digital Devices GmbH\n");
|
||||
res = ddb_class_create();
|
||||
if (res)
|
||||
return res;
|
||||
res = platform_driver_probe(&octonet_driver, octonet_probe);
|
||||
if (res) {
|
||||
ddb_class_destroy();
|
||||
return res;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __exit void exit_octonet(void)
|
||||
{
|
||||
platform_driver_unregister(&octonet_driver);
|
||||
ddb_class_destroy();
|
||||
}
|
||||
|
||||
module_init(init_octonet);
|
||||
module_exit(exit_octonet);
|
||||
|
||||
MODULE_DESCRIPTION("GPL");
|
||||
MODULE_AUTHOR("Marcus and Ralph Metzler, Metzler Brothers Systementwicklung GbR");
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION("0.6");
|
Reference in New Issue
Block a user