initial commit from dddvb-0.9.19c

This commit is contained in:
mvoelkel
2015-08-05 17:22:42 +02:00
commit 9e2128c4fb
121 changed files with 90381 additions and 0 deletions

8
ddbridge/Kbuild Normal file
View 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
View 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

File diff suppressed because it is too large Load Diff

275
ddbridge/ddbridge-i2c.c Normal file
View 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 = &reg, .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 = &reg, .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
View 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 = &reg, .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 = &reg, .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

File diff suppressed because it is too large Load Diff

491
ddbridge/ddbridge-ns.c Normal file
View 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
View 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
View 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
View 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
View 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");