1
0
mirror of https://github.com/DigitalDevices/dddvb.git synced 2023-10-10 13:37:43 +02:00

adapt to current mainline kernel dvb-core

This commit is contained in:
none 2020-08-29 15:32:42 +02:00
parent 83f5b45928
commit 7f19a0c04b
58 changed files with 2708 additions and 1391 deletions

View File

@ -2,10 +2,15 @@ kernelver ?= $(shell uname -r)
KDIR ?= /lib/modules/$(kernelver)/build KDIR ?= /lib/modules/$(kernelver)/build
PWD := $(shell pwd) PWD := $(shell pwd)
MODDEFS := CONFIG_DVB_CORE=m CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_DRXK=m CONFIG_DVB_TDA18271C2DD=m CONFIG_DVB_CXD2099=m CONFIG_DVB_LNBP21=m CONFIG_DVB_STV090x=m CONFIG_DVB_STV6110x=m CONFIG_DVB_STV0367=m CONFIG_DVB_TDA18212=m CONFIG_DVB_STV0367DD=m CONFIG_DVB_TDA18212DD=m CONFIG_DVB_OCTONET=m CONFIG_DVB_CXD2843=m CONFIG_DVB_STV0910=m CONFIG_DVB_STV6111=m CONFIG_DVB_LNBH25=m CONFIG_DVB_MXL5XX=m CONFIG_DVB_NET=m MODDEFS := CONFIG_DVB_CORE=m CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_DRXK=m CONFIG_DVB_TDA18271C2DD=m CONFIG_DVB_CXD2099=m CONFIG_DVB_LNBP21=m CONFIG_DVB_STV090x=m CONFIG_DVB_STV6110x=m CONFIG_DVB_STV0367=m CONFIG_DVB_TDA18212=m CONFIG_DVB_STV0367DD=m CONFIG_DVB_TDA18212DD=m CONFIG_DVB_OCTONET=m CONFIG_DVB_CXD2843=m CONFIG_DVB_STV0910=m CONFIG_DVB_STV6111=m CONFIG_DVB_LNBH25=m CONFIG_DVB_MXL5XX=m CONFIG_DVB_NET=y DDDVB=y
KBUILD_EXTMOD = $(PWD)
DDDVB_INC = "-I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux -I$(KBUILD_EXTMOD)/frontends"
all: all:
$(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) $(MODDEFS) modules $(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) $(MODDEFS) modules NOSTDINC_FLAGS=$(DDDVB_INC)
$(MAKE) -C apps $(MAKE) -C apps
libdddvb: libdddvb:
@ -22,6 +27,7 @@ dep:
install: all install: all
$(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) modules_install $(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) modules_install
depmod -a
clean: clean:
rm -rf */.*.o.d */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules* rm -rf */.*.o.d */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*

View File

@ -3,9 +3,11 @@ EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843 -DCONFIG_DVB_LNBP21 -DCONFIG_DVB_STV090x -D
ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o #mci-objs = ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o ddbridge-io.o
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o #mci.o
obj-$(CONFIG_DVB_OCTONET) += octonet.o obj-$(CONFIG_DVB_OCTONET) += octonet.o
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends #EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends
EXTRA_CFLAGS += -Idrivers/media/common/tuners #EXTRA_CFLAGS += -Idrivers/media/common/tuners
NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core #NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core

View File

@ -1,14 +1,15 @@
# #
# Makefile for the ddbridge device driver # Makefile for the ddbridge device driver
# #
#NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux -I$(KBUILD_EXTMOD)/dvb-frontends -I$(KBUILD_EXTMOD)/tuners
ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o
octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o
obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o
obj-$(CONFIG_DVB_OCTONET) += octonet.o obj-$(CONFIG_DVB_OCTONET) += octonet.o
ccflags-y += -Idrivers/media/dvb-core/ #ccflags-y += -Idrivers/media/include/linux/
ccflags-y += -Idrivers/media/dvb-frontends/ #ccflags-y += -Idrivers/media/dvb-frontends/
ccflags-y += -Idrivers/media/tuners/ #ccflags-y += -Idrivers/media/tuners/

View File

@ -24,7 +24,7 @@
#include "ddbridge.h" #include "ddbridge.h"
#include "ddbridge-i2c.h" #include "ddbridge-i2c.h"
#include "ddbridge-io.h" #include "ddbridge-io.h"
#include "dvb_net.h" #include <media/dvb_net.h>
struct workqueue_struct *ddb_wq; struct workqueue_struct *ddb_wq;
@ -103,6 +103,7 @@ struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr,
irq->data = data; irq->data = data;
return irq; return irq;
} }
EXPORT_SYMBOL(ddb_irq_set);
static void ddb_set_dma_table(struct ddb_io *io) static void ddb_set_dma_table(struct ddb_io *io)
{ {
@ -486,9 +487,8 @@ static void ddb_output_start_unlocked(struct ddb_output *output)
} }
if (output->port->class != DDB_PORT_MOD) if (output->port->class != DDB_PORT_MOD)
ddbwritel(dev, con | 1, TS_CONTROL(output)); ddbwritel(dev, con | 1, TS_CONTROL(output));
if (output->dma) { if (output->dma)
output->dma->running = 1; output->dma->running = 1;
}
} }
static void ddb_output_start(struct ddb_output *output) static void ddb_output_start(struct ddb_output *output)
@ -669,7 +669,7 @@ static u32 ddb_output_free(struct ddb_output *output)
if (output->dma->cbuf != idx) { if (output->dma->cbuf != idx) {
if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && if ((((output->dma->cbuf + 1) % output->dma->num) == idx) &&
(output->dma->size - output->dma->coff <= 2*188)) (output->dma->size - output->dma->coff <= 2 * 188))
return 0; return 0;
return 188; return 188;
} }
@ -679,25 +679,6 @@ static u32 ddb_output_free(struct ddb_output *output)
return 0; return 0;
} }
#if 0
static u32 ddb_dma_free(struct ddb_dma *dma)
{
u32 idx, off, stat = dma->stat;
s32 p1, p2, diff;
idx = (stat >> 11) & 0x1f;
off = (stat & 0x7ff) << 7;
p1 = idx * dma->size + off;
p2 = dma->cbuf * dma->size + dma->coff;
diff = p1 - p2;
if (diff <= 0)
diff += dma->num * dma->size;
return diff;
}
#endif
static ssize_t ddb_output_write(struct ddb_output *output, static ssize_t ddb_output_write(struct ddb_output *output,
const __user u8 *buf, size_t count) const __user u8 *buf, size_t count)
{ {
@ -753,79 +734,6 @@ static ssize_t ddb_output_write(struct ddb_output *output,
return count - left; return count - left;
} }
#if 0
static u32 ddb_input_free_bytes(struct ddb_input *input)
{
struct ddb *dev = input->port->dev;
u32 idx, off, stat = input->dma->stat;
u32 ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(input->dma));
idx = (stat >> 11) & 0x1f;
off = (stat & 0x7ff) << 7;
if (ctrl & 4)
return 0;
if (input->dma->cbuf != idx)
return 1;
return 0;
}
static s32 ddb_output_used_bufs(struct ddb_output *output)
{
u32 idx, off, stat, ctrl;
s32 diff;
spin_lock_irq(&output->dma->lock);
stat = output->dma->stat;
ctrl = output->dma->ctrl;
spin_unlock_irq(&output->dma->lock);
idx = (stat >> 11) & 0x1f;
off = (stat & 0x7ff) << 7;
if (ctrl & 4)
return 0;
diff = output->dma->cbuf - idx;
if (diff == 0 && off < output->dma->coff)
return 0;
if (diff <= 0)
diff += output->dma->num;
return diff;
}
static s32 ddb_input_free_bufs(struct ddb_input *input)
{
u32 idx, off, stat, ctrl;
s32 free;
spin_lock_irq(&input->dma->lock);
ctrl = input->dma->ctrl;
stat = input->dma->stat;
spin_unlock_irq(&input->dma->lock);
if (ctrl & 4)
return 0;
idx = (stat >> 11) & 0x1f;
off = (stat & 0x7ff) << 7;
free = input->dma->cbuf - idx;
if (free == 0 && off < input->dma->coff)
return 0;
if (free <= 0)
free += input->dma->num;
return free - 1;
}
static u32 ddb_output_ok(struct ddb_output *output)
{
struct ddb_input *input = output->port->input[0];
s32 diff;
diff = ddb_input_free_bufs(input) - ddb_output_used_bufs(output);
if (diff > 0)
return 1;
return 0;
}
#endif
static u32 ddb_input_avail(struct ddb_input *input) static u32 ddb_input_avail(struct ddb_input *input)
{ {
struct ddb *dev = input->port->dev; struct ddb *dev = input->port->dev;
@ -1125,20 +1033,20 @@ static struct dvb_frontend_ops dummy_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBS, SYS_DVBS2 }, .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBS, SYS_DVBS2 },
.info = { .info = {
.name = "DUMMY DVB-C/C2 DVB-T/T2", .name = "DUMMY DVB-C/C2 DVB-T/T2",
.frequency_stepsize = 166667, /* DVB-T only */ .frequency_stepsize_hz = 166667, /* DVB-T only */
.frequency_min = 47000000, /* DVB-T: 47125000 */ .frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */ .frequency_max_hz = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 870000, .symbol_rate_min = 870000,
.symbol_rate_max = 11700000, .symbol_rate_max = 11700000,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO | FE_CAN_QAM_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 | FE_CAN_FEC_4_5 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION
}, },
.release = dummy_release, .release = dummy_release,
.read_status = dummy_read_status, .read_status = dummy_read_status,
@ -1484,29 +1392,6 @@ static int tuner_attach_stv6111(struct ddb_input *input, int type)
return 0; return 0;
} }
#if 0
static int start_input(struct ddb_input *input)
{
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
if (!dvb->users)
ddb_input_start_all(input);
return ++dvb->users;
}
static int stop_input(struct ddb_input *input)
{
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
if (--dvb->users)
return dvb->users;
ddb_input_stop_all(input);
return 0;
}
#endif
static int start_feed(struct dvb_demux_feed *dvbdmxfeed) static int start_feed(struct dvb_demux_feed *dvbdmxfeed)
{ {
struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
@ -1603,7 +1488,7 @@ static int dvb_register_adapters(struct ddb *dev)
if (adapter_alloc >= 3 || dev->link[0].info->type == DDB_MOD || if (adapter_alloc >= 3 || dev->link[0].info->type == DDB_MOD ||
dev->link[0].info->type == DDB_OCTONET || dev->link[0].info->type == DDB_OCTONET ||
dev->link[0].info->type == DDB_OCTOPRO ) { dev->link[0].info->type == DDB_OCTOPRO) {
port = &dev->port[0]; port = &dev->port[0];
adap = port->dvb[0].adap; adap = port->dvb[0].adap;
ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE,
@ -2118,16 +2003,6 @@ static void ddb_port_probe(struct ddb_port *port)
port->class = DDB_PORT_MOD; port->class = DDB_PORT_MOD;
return; return;
} }
#if 0
if (link->info->type == DDB_OCTOPRO_HDIN) {
if (port->nr == 0) {
dev->link[l].info->type = DDB_OCTOPUS;
port->name = "HDIN";
port->class = DDB_PORT_LOOP;
}
return;
}
#endif
if (link->info->type == DDB_OCTOPUS_MAX) { if (link->info->type == DDB_OCTOPUS_MAX) {
port->name = "DUAL DVB-S2 MAX"; port->name = "DUAL DVB-S2 MAX";
port->type_name = "MXL5XX"; port->type_name = "MXL5XX";
@ -2447,17 +2322,15 @@ static void input_tasklet(unsigned long data)
dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma));
dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma));
#if 1
{ {
u32 packet_loss = dma->packet_loss; u32 packet_loss = dma->packet_loss;
u32 cur_counter = TS_STAT(input) & 0xFFFF; u32 cur_counter = ddbreadl(dev, TS_STAT(input)) & 0xffff;
if ( cur_counter < (packet_loss & 0xFFFF) ) if (cur_counter < (packet_loss & 0xffff))
packet_loss += 0x10000; packet_loss += 0x10000;
packet_loss = ((packet_loss & 0xFFFF0000) | cur_counter); packet_loss = ((packet_loss & 0xffff0000) | cur_counter);
dma->packet_loss = packet_loss; dma->packet_loss = packet_loss;
} }
#endif
if (4 & dma->ctrl) if (4 & dma->ctrl)
dma->stall_count++; dma->stall_count++;
if (input->redi) if (input->redi)
@ -2468,7 +2341,7 @@ static void input_tasklet(unsigned long data)
spin_unlock_irqrestore(&dma->lock, flags); spin_unlock_irqrestore(&dma->lock, flags);
} }
#if 0 #ifdef OPTIMIZE_TASKLETS
static void input_handler(unsigned long data) static void input_handler(unsigned long data)
{ {
struct ddb_input *input = (struct ddb_input *)data; struct ddb_input *input = (struct ddb_input *)data;
@ -2530,7 +2403,7 @@ unlock_exit:
spin_unlock_irqrestore(&dma->lock, flags); spin_unlock_irqrestore(&dma->lock, flags);
} }
#if 0 #ifdef OPTIMIZE_TASKLETS
static void output_handler(void *data) static void output_handler(void *data)
{ {
struct ddb_output *output = (struct ddb_output *)data; struct ddb_output *output = (struct ddb_output *)data;
@ -2620,10 +2493,6 @@ static void ddb_dma_init(struct ddb_io *io, int nr, int out, int irq_nr)
dma->div = 1; dma->div = 1;
} }
ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma)); ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma));
#if 0
dev_info(io->port->dev->dev, "init link %u, io %u, dma %u, dmaregs %08x bufregs %08x\n",
io->port->lnr, io->nr, nr, dma->regs, dma->bufregs);
#endif
} }
static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr) static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr)
@ -2648,10 +2517,6 @@ static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr)
if (port->lnr) if (port->lnr)
dma_nr += 32 + (port->lnr - 1) * 8; dma_nr += 32 + (port->lnr - 1) * 8;
#if 0
dev_info(dev->dev, "init link %u, input %u, handler %u\n",
port->lnr, nr, dma_nr + base);
#endif
ddb_irq_set(dev, 0, dma_nr + base, &input_handler, input); ddb_irq_set(dev, 0, dma_nr + base, &input_handler, input);
ddb_dma_init(input, dma_nr, 0, dma_nr + base); ddb_dma_init(input, dma_nr, 0, dma_nr + base);
} }
@ -2669,10 +2534,6 @@ static void ddb_output_init(struct ddb_port *port, int nr)
rm = io_regmap(output, 1); rm = io_regmap(output, 1);
output->regs = DDB_LINK_TAG(port->lnr) | output->regs = DDB_LINK_TAG(port->lnr) |
(rm->output->base + rm->output->size * nr); (rm->output->base + rm->output->size * nr);
#if 0
dev_info(dev->dev, "init link %u, output %u, regs %08x\n",
port->lnr, nr, output->regs);
#endif
if (dev->has_dma) { if (dev->has_dma) {
const struct ddb_regmap *rm0 = io_regmap(output, 0); const struct ddb_regmap *rm0 = io_regmap(output, 0);
u32 base = rm0->irq_base_odma; u32 base = rm0->irq_base_odma;
@ -3683,7 +3544,7 @@ static ssize_t temp_show(struct device *device,
l = attr->attr.name[5] - 0x30; l = attr->attr.name[5] - 0x30;
link = &dev->link[l]; link = &dev->link[l];
if (link->info->type == DDB_MOD ) { if (link->info->type == DDB_MOD) {
if (link->info->version >= 2) { if (link->info->version >= 2) {
temp = 0xffff & ddbreadl(dev, TEMPMON2_BOARD); temp = 0xffff & ddbreadl(dev, TEMPMON2_BOARD);
temp = (temp * 1000) >> 8; temp = (temp * 1000) >> 8;
@ -3755,25 +3616,6 @@ static ssize_t ctemp_show(struct device *device,
return sprintf(buf, "%d\n", temp); return sprintf(buf, "%d\n", temp);
} }
#if 0
static ssize_t qam_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct ddb *dev = dev_get_drvdata(device);
struct i2c_adapter *adap;
u8 tmp[4];
s16 i, q;
adap = &dev->i2c[1].adap;
if (i2c_read_regs16(adap, 0x1f, 0xf480, tmp, 4) < 0)
return sprintf(buf, "read_error\n");
i = (s16)(((u16)tmp[1]) << 14) | (((u16)tmp[0]) << 6);
q = (s16)(((u16)tmp[3]) << 14) | (((u16)tmp[2]) << 6);
return sprintf(buf, "%d %d\n", i, q);
}
#endif
static ssize_t mod_show(struct device *device, static ssize_t mod_show(struct device *device,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
@ -3954,32 +3796,6 @@ static ssize_t redirect_store(struct device *device,
return count; return count;
} }
#if 0
/* A L P I AAAAAALLPPPPPPII */
/* AAAAAAAA LLLLLLLL PPPPPPII */
static ssize_t redirect2_show(struct device *device,
struct device_attribute *attr, char *buf)
{
return 0;
}
static ssize_t redirect2_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int i, p;
int res;
if (sscanf(buf, "%x %x\n", &i, &p) != 2)
return -EINVAL;
res = ddb_redirect(i, p);
if (res < 0)
return res;
dev_info(device, "redirect: %02x, %02x\n", i, p);
return count;
}
#endif
static ssize_t gap_show(struct device *device, static ssize_t gap_show(struct device *device,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
@ -4137,9 +3953,6 @@ static struct device_attribute ddb_attrs[] = {
__ATTR_MRO(devid3, devid_show), __ATTR_MRO(devid3, devid_show),
__ATTR_RO(hwid), __ATTR_RO(hwid),
__ATTR_RO(regmap), __ATTR_RO(regmap),
#if 0
__ATTR_RO(qam),
#endif
__ATTR(redirect, 0664, redirect_show, redirect_store), __ATTR(redirect, 0664, redirect_show, redirect_store),
__ATTR_MRO(snr, bsnr_show), __ATTR_MRO(snr, bsnr_show),
__ATTR_RO(bpsnr), __ATTR_RO(bpsnr),
@ -4239,7 +4052,6 @@ static void ddb_device_attrs_del(struct ddb *dev)
if (dev->link[i].info && if (dev->link[i].info &&
dev->link[i].info->temp_num) dev->link[i].info->temp_num)
device_remove_file(dev->ddb_dev, &ddb_attrs_temp[i]); device_remove_file(dev->ddb_dev, &ddb_attrs_temp[i]);
for (i = 0; i < dev->link[0].info->temp_num; i++)
for (i = 0; i < dev->link[0].info->port_num; i++) for (i = 0; i < dev->link[0].info->port_num; i++)
device_remove_file(dev->ddb_dev, &ddb_attrs_mod[i]); device_remove_file(dev->ddb_dev, &ddb_attrs_mod[i]);
for (i = 0; i < dev->link[0].info->fan_num; i++) for (i = 0; i < dev->link[0].info->fan_num; i++)
@ -4377,7 +4189,9 @@ static void link_tasklet(unsigned long data)
static void gtl_irq_handler(void *priv) static void gtl_irq_handler(void *priv)
{ {
struct ddb_link *link = (struct ddb_link *)priv; struct ddb_link *link = (struct ddb_link *)priv;
#if 1 #ifdef USE_LINK_TASKLET
tasklet_schedule(&link->tasklet);
#else
struct ddb *dev = link->dev; struct ddb *dev = link->dev;
u32 s, l = link->nr, tag = DDB_LINK_TAG(link->nr); u32 s, l = link->nr, tag = DDB_LINK_TAG(link->nr);
@ -4389,8 +4203,6 @@ static void gtl_irq_handler(void *priv)
LINK_IRQ_HANDLE(l, 3); LINK_IRQ_HANDLE(l, 3);
LINK_IRQ_HANDLE(l, 24); LINK_IRQ_HANDLE(l, 24);
} }
#else
tasklet_schedule(&link->tasklet);
#endif #endif
} }
@ -4434,7 +4246,7 @@ static int ddb_gtl_init_link(struct ddb *dev, u32 l)
subid & 0xffff, subid >> 16); subid & 0xffff, subid >> 16);
if (link->info->type != DDB_OCTOPUS_MAX_CT && if (link->info->type != DDB_OCTOPUS_MAX_CT &&
link->info->type != DDB_OCTOPUS_MAX && link->info->type != DDB_OCTOPUS_MAX &&
link->info->type != DDB_OCTOPUS_MCI ) { link->info->type != DDB_OCTOPUS_MCI) {
dev_info(dev->dev, dev_info(dev->dev,
"Detected GT link but found invalid ID %08x. You might have to update (flash) the add-on card first.", "Detected GT link but found invalid ID %08x. You might have to update (flash) the add-on card first.",
id); id);

View File

@ -801,7 +801,7 @@ static const struct ddb_device_id ddb_device_ids[] = {
DDB_DEVID(0x0013, 0x0044, ddb_ci_s2_pro_a), DDB_DEVID(0x0013, 0x0044, ddb_ci_s2_pro_a),
DDB_DEVID(0x0020, 0x0012, ddb_gtl_mini), DDB_DEVID(0x0020, 0x0012, ddb_gtl_mini),
/* Modulators */ /* Modulators */
DDB_DEVID(0x0201, 0x0001, ddb_mod), DDB_DEVID(0x0201, 0x0001, ddb_mod),
DDB_DEVID(0x0201, 0x0002, ddb_mod), DDB_DEVID(0x0201, 0x0002, ddb_mod),
DDB_DEVID(0x0201, 0x0004, ddb_mod_4), /* dummy entry ! */ DDB_DEVID(0x0201, 0x0004, ddb_mod_4), /* dummy entry ! */

View File

@ -35,33 +35,30 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
stat = wait_for_completion_timeout(&i2c->completion, HZ); stat = wait_for_completion_timeout(&i2c->completion, HZ);
val = ddbreadl(dev, i2c->regs + I2C_COMMAND); val = ddbreadl(dev, i2c->regs + I2C_COMMAND);
if (stat == 0) { if (stat == 0) {
u32 istat = ddbreadl(dev, INTERRUPT_STATUS);
dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n", dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n",
dev->nr, i2c->nr, i2c->link); dev->nr, i2c->nr, i2c->link);
#if 1 dev_err(dev->dev, "DDBridge IRS %08x\n", istat);
{
u32 istat = ddbreadl(dev, INTERRUPT_STATUS);
dev_err(dev->dev, "DDBridge IRS %08x\n", istat); if (i2c->link) {
if (i2c->link) { u32 listat =
u32 listat = ddbreadl(dev,
ddbreadl(dev, DDB_LINK_TAG(i2c->link) |
DDB_LINK_TAG(i2c->link) | INTERRUPT_STATUS);
INTERRUPT_STATUS); dev_err(dev->dev,
dev_err(dev->dev, "DDBridge link %u IRS %08x\n",
"DDBridge link %u IRS %08x\n", i2c->link, listat);
i2c->link, listat); }
} if (istat & 1) {
if (istat & 1) { ddbwritel(dev, istat & 1, INTERRUPT_ACK);
ddbwritel(dev, istat & 1, INTERRUPT_ACK); } else {
} else { u32 mon = ddbreadl(dev,
u32 mon = ddbreadl(dev, i2c->regs + I2C_MONITOR);
i2c->regs + I2C_MONITOR);
dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n",
dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n", val, mon);
val, mon);
}
} }
#endif
return -EIO; return -EIO;
} }
val &= 0x70000; val &= 0x70000;

View File

@ -1,4 +1,4 @@
// SPDX-License-Identifier: GPL-2.0 /* SPDX-License-Identifier: GPL-2.0 */
/* /*
* ddbridge-i2c.h: Digital Devices bridge i2c driver * ddbridge-i2c.h: Digital Devices bridge i2c driver
* *

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* ddbridge-io.c: Digital Devices bridge I/O functions * ddbridge-io.c: Digital Devices bridge I/O functions
* *

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* ddbridge-io.h: Digital Devices bridge I/O functions * ddbridge-io.h: Digital Devices bridge I/O functions
* *
@ -64,7 +65,7 @@ static inline u32 ddblreadl0(struct ddb_link *link, u32 adr)
return readl(link->dev->regs + adr); return readl(link->dev->regs + adr);
} }
#if 0 #ifdef DEBUG_GTLW
static inline void gtlw(struct ddb_link *link) static inline void gtlw(struct ddb_link *link)
{ {
u32 count = 0; u32 count = 0;

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* ddbridge-m4.c: Digital Devices MAX M4 driver * ddbridge-m4.c: Digital Devices MAX M4 driver
* *
@ -335,6 +336,7 @@ static int set_parameters(struct dvb_frontend *fe)
{ {
struct m4 *state = fe->demodulator_priv; struct m4 *state = fe->demodulator_priv;
int res; int res;
//struct dtv_frontend_properties *p = &fe->dtv_property_cache;
stop(fe); stop(fe);
@ -343,6 +345,7 @@ static int set_parameters(struct dvb_frontend *fe)
state->iq_constellation_point_max = 0; state->iq_constellation_point_max = 0;
state->iq_constellation_tap = 0; state->iq_constellation_tap = 0;
//printk("bw = %u\n", p->bandwidth_hz);
switch (fe->dtv_property_cache.delivery_system) { switch (fe->dtv_property_cache.delivery_system) {
case SYS_DVBS: case SYS_DVBS:
case SYS_DVBS2: case SYS_DVBS2:
@ -450,7 +453,7 @@ static void release(struct dvb_frontend *fe)
kfree(state); kfree(state);
} }
static int get_algo(struct dvb_frontend *fe) static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{ {
return DVBFE_ALGO_HW; return DVBFE_ALGO_HW;
} }
@ -470,21 +473,21 @@ static struct dvb_frontend_ops m4_ops = {
SYS_DVBS, SYS_DVBS2, SYS_ISDBS, }, SYS_DVBS, SYS_DVBS2, SYS_ISDBS, },
.info = { .info = {
.name = "M4", .name = "M4",
.frequency_min = 950000, /* DVB-T: 47125000 */ .frequency_min_hz = 47125000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */ .frequency_max_hz = 2150000000, /* DVB-C: 862000000 */
.symbol_rate_min = 100000, .symbol_rate_min = 100000,
.symbol_rate_max = 100000000, .symbol_rate_max = 100000000,
.frequency_stepsize = 0, .frequency_stepsize_hz = 0,
.frequency_tolerance = 0, .frequency_tolerance_hz = 0,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO | FE_CAN_QAM_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 | FE_CAN_FEC_4_5 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION
}, },
.release = release, .release = release,
.get_frontend_algo = get_algo, .get_frontend_algo = get_algo,

View File

@ -458,11 +458,9 @@ static pci_ers_result_t ddb_pci_error_detected(struct pci_dev *pdev,
{ {
switch (state) { switch (state) {
case pci_channel_io_frozen: case pci_channel_io_frozen:
return PCI_ERS_RESULT_CAN_RECOVER; return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_perm_failure: case pci_channel_io_perm_failure:
return PCI_ERS_RESULT_DISCONNECT; return PCI_ERS_RESULT_DISCONNECT;
break;
case pci_channel_io_normal: case pci_channel_io_normal:
default: default:
break; break;

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* ddbridge-max.c: Digital Devices MAX card line support functions * ddbridge-max.c: Digital Devices MAX card line support functions
* *
@ -67,7 +68,7 @@ static int max_emulate_switch(struct dvb_frontend *fe,
{ {
int input; int input;
if (len !=4) if (len != 4)
return -1; return -1;
if ((cmd[0] != 0xe0) || (cmd[1] != 0x10) || (cmd[2] != 0x39)) if ((cmd[0] != 0xe0) || (cmd[1] != 0x10) || (cmd[2] != 0x39))
@ -490,9 +491,6 @@ int ddb_fe_attach_mxl5xx(struct ddb_input *input)
/* MAX MCI related functions */ /* MAX MCI related functions */
extern struct mci_cfg ddb_max_sx8_cfg;
extern struct mci_cfg ddb_max_m4_cfg;
int ddb_fe_attach_mci(struct ddb_input *input, u32 type) int ddb_fe_attach_mci(struct ddb_input *input, u32 type)
{ {
struct ddb *dev = input->port->dev; struct ddb *dev = input->port->dev;

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* ddbridge-mci.c: Digital Devices microcode interface * ddbridge-mci.c: Digital Devices microcode interface
* *
@ -38,7 +39,7 @@ static int mci_reset(struct mci *state)
msleep(300); msleep(300);
ddblwritel(link, 0, MCI_CONTROL); ddblwritel(link, 0, MCI_CONTROL);
while(1) { while (1) {
status = ddblreadl(link, MCI_CONTROL); status = ddblreadl(link, MCI_CONTROL);
if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY) if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY)
break; break;
@ -46,7 +47,7 @@ static int mci_reset(struct mci *state)
break; break;
msleep(50); msleep(50);
} }
if ((status & MCI_CONTROL_READY) == 0 ) if ((status & MCI_CONTROL_READY) == 0)
return -1; return -1;
if (link->ids.device == 0x0009 || link->ids.device == 0x000b) if (link->ids.device == 0x0009 || link->ids.device == 0x000b)
ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG); ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG);
@ -85,13 +86,15 @@ static int ddb_mci_cmd_raw_unlocked(struct mci *state,
if (stat == 0) { if (stat == 0) {
u32 istat = ddblreadl(link, INTERRUPT_STATUS); u32 istat = ddblreadl(link, INTERRUPT_STATUS);
printk("MCI timeout\n"); dev_err(state->base->link->dev->dev, "MCI timeout\n");
val = ddblreadl(link, MCI_CONTROL); val = ddblreadl(link, MCI_CONTROL);
if (val == 0xffffffff) { if (val == 0xffffffff) {
printk("Lost PCIe link!\n"); dev_err(state->base->link->dev->dev,
"Lost PCIe link!\n");
return -EIO; return -EIO;
} else { } else {
printk("DDBridge IRS %08x link %u\n", istat, link->nr); dev_err(state->base->link->dev->dev,
"DDBridge IRS %08x link %u\n", istat, link->nr);
if (istat & 1) if (istat & 1)
ddblwritel(link, istat, INTERRUPT_ACK); ddblwritel(link, istat, INTERRUPT_ACK);
if (link->nr) if (link->nr)
@ -186,8 +189,7 @@ int ddb_mci_get_snr(struct dvb_frontend *fe)
p->cnr.len = 1; p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL; p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].svalue = (s64) mci-> p->cnr.stat[0].svalue = (s64) mci->signal_info.dvbs2_signal_info.signal_to_noise * 10;
signal_info.dvbs2_signal_info.signal_to_noise * 10;
return 0; return 0;
} }
@ -259,7 +261,6 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p)
{ {
u32 pls_code = u32 pls_code =
mci->signal_info.dvbs2_signal_info.pls_code; mci->signal_info.dvbs2_signal_info.pls_code;
p->frequency = p->frequency =
mci->signal_info.dvbs2_signal_info.frequency / 1000; mci->signal_info.dvbs2_signal_info.frequency / 1000;
p->delivery_system = p->delivery_system =
@ -270,8 +271,7 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p)
p->delivery_system = SYS_DVBS2; p->delivery_system = SYS_DVBS2;
p->rolloff = p->rolloff =
ro_lut[mci->signal_info. ro_lut[mci->signal_info.dvbs2_signal_info.roll_off & 7];
dvbs2_signal_info.roll_off & 7];
p->pilot = (pls_code & 1) ? PILOT_ON : PILOT_OFF; p->pilot = (pls_code & 1) ? PILOT_ON : PILOT_OFF;
p->fec_inner = modcod2fec[modcod]; p->fec_inner = modcod2fec[modcod];
p->modulation = modcod2mod[modcod]; p->modulation = modcod2mod[modcod];
@ -314,8 +314,8 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p)
p->cnr.len = 1; p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL; p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].svalue = (s64) mci-> p->cnr.stat[0].svalue = (s64)
signal_info.dvbs2_signal_info.signal_to_noise * 10; mci->signal_info.dvbs2_signal_info.signal_to_noise * 10;
p->strength.len = 1; p->strength.len = 1;
p->strength.stat[0].scale = FE_SCALE_DECIBEL; p->strength.stat[0].scale = FE_SCALE_DECIBEL;

View File

@ -648,8 +648,7 @@ struct mci_result {
struct { struct {
u8 Mode; // FFT Mode 1,2,3 u8 Mode; // FFT Mode 1,2,3
u8 GuardInterval; // 1/32, 1/16, 1/8, /14 u8 GuardInterval; // 1/32, 1/16, 1/8, /14
u8 TMCCInfo[13]; // TMCC B20 - B121, byte 0 bit 7: B20, byte 12 bit 2: B121
u8 TMCCInfo[13]; // TMCC B20 - B121, byte 0 bit 7: B20, byte 12 bit 2: B121
} ISDBT_TMCCInfo; } ISDBT_TMCCInfo;
struct { struct {
@ -710,7 +709,7 @@ struct mci_result {
/* DVB-T2 L1-Post Signalling Data ( ETSI EN 302 755 V1.4.1 Chapter 7.2.3 ) */ /* DVB-T2 L1-Post Signalling Data ( ETSI EN 302 755 V1.4.1 Chapter 7.2.3 ) */
#define L1POST_SUB_SLICES_PER_FRAME(p) (((u16)(p)[ 0] & 0x7F) | (p)[ 1]) #define L1POST_SUB_SLICES_PER_FRAME(p) (((u16)(p)[0] & 0x7F) | (p)[1])
#define L1POST_NUM_PLP(p) ((p)[2] & 0xFF) #define L1POST_NUM_PLP(p) ((p)[2] & 0xFF)
#define L1POST_NUM_AUX(p) ((p)[3] & 0x0F) #define L1POST_NUM_AUX(p) ((p)[3] & 0x0F)
#define L1POST_AUX_CONFIG_RFU(p) ((p)[4] & 0xFF) #define L1POST_AUX_CONFIG_RFU(p) ((p)[4] & 0xFF)
@ -750,8 +749,6 @@ struct mci_base {
void *key; void *key;
struct ddb_link *link; struct ddb_link *link;
struct completion completion; struct completion completion;
struct i2c_adapter *i2c;
struct mutex i2c_lock;
struct mutex tuner_lock; struct mutex tuner_lock;
struct mutex mci_lock; struct mutex mci_lock;
int count; int count;
@ -788,4 +785,7 @@ int ddb_mci_get_info(struct mci *mci);
int ddb_mci_get_strength(struct dvb_frontend *fe); int ddb_mci_get_strength(struct dvb_frontend *fe);
void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p); void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p);
extern struct mci_cfg ddb_max_sx8_cfg;
extern struct mci_cfg ddb_max_m4_cfg;
#endif #endif

View File

@ -441,11 +441,11 @@ static int ns_start(struct dvbnss *nss)
reg |= 0x40; reg |= 0x40;
if (nss->params.flags & DVB_NS_IPV6) if (nss->params.flags & DVB_NS_IPV6)
reg |= 0x80; reg |= 0x80;
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
STREAM_CONTROL(dns->nr));
if (dns->fe != input) if (dns->fe != input)
ddb_dvb_ns_input_start(dns->fe); ddb_dvb_ns_input_start(dns->fe);
ddb_dvb_ns_input_start(input); ddb_dvb_ns_input_start(input);
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
STREAM_CONTROL(dns->nr));
return 0; return 0;
} }

View File

@ -501,7 +501,7 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
return 0; return 0;
} }
static int get_algo(struct dvb_frontend *fe) static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{ {
return DVBFE_ALGO_HW; return DVBFE_ALGO_HW;
} }
@ -541,10 +541,10 @@ static struct dvb_frontend_ops sx8_ops = {
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */ .xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
.info = { .info = {
.name = "DVB-S/S2X", .name = "DVB-S/S2X",
.frequency_min = 950000, .frequency_min_hz = 950000000,
.frequency_max = 2150000, .frequency_max_hz = 2150000000,
.frequency_stepsize = 0, .frequency_stepsize_hz = 0,
.frequency_tolerance = 0, .frequency_tolerance_hz = 0,
.symbol_rate_min = 100000, .symbol_rate_min = 100000,
.symbol_rate_max = 100000000, .symbol_rate_max = 100000000,
.caps = FE_CAN_INVERSION_AUTO | .caps = FE_CAN_INVERSION_AUTO |

View File

@ -60,22 +60,20 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <linux/io.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/dvb/ca.h> #include <linux/dvb/ca.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/io.h>
#include "dvb_netstream.h" #include "dvb_netstream.h"
#include "dmxdev.h" #include <media/dmxdev.h>
#include "dvbdev.h" #include <media/dvbdev.h>
#include "dvb_demux.h" #include <media/dvb_demux.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "dvb_ringbuffer.h" #include <media/dvb_ringbuffer.h>
#include "dvb_ca_en50221.h" #include <media/dvb_ca_en50221.h>
#include "dvb_net.h" #include <media/dvb_net.h>
#include "tda18271c2dd.h" #include "tda18271c2dd.h"
#include "stv6110x.h" #include "stv6110x.h"
@ -238,7 +236,7 @@ struct ddb_dvb {
enum fe_sec_tone_mode tone; enum fe_sec_tone_mode tone;
enum fe_sec_voltage voltage; enum fe_sec_voltage voltage;
int (*i2c_gate_ctrl)(struct dvb_frontend *, int); int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int val);
int (*set_voltage)(struct dvb_frontend *fe, int (*set_voltage)(struct dvb_frontend *fe,
enum fe_sec_voltage voltage); enum fe_sec_voltage voltage);
int (*set_input)(struct dvb_frontend *fe, int input); int (*set_input)(struct dvb_frontend *fe, int input);
@ -408,7 +406,7 @@ struct ddb_lnb {
}; };
struct ddb_irq { struct ddb_irq {
void (*handler)(void *); void (*handler)(void *data);
void *data; void *data;
}; };
@ -542,7 +540,7 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg);
int ddbridge_mod_init(struct ddb *dev); int ddbridge_mod_init(struct ddb *dev);
void ddbridge_mod_output_stop(struct ddb_output *output); void ddbridge_mod_output_stop(struct ddb_output *output);
int ddbridge_mod_output_start(struct ddb_output *output); int ddbridge_mod_output_start(struct ddb_output *output);
void ddbridge_mod_rate_handler(void *); void ddbridge_mod_rate_handler(void *data);
void ddb_device_destroy(struct ddb *dev); void ddb_device_destroy(struct ddb *dev);
void ddb_nsd_detach(struct ddb *dev); void ddb_nsd_detach(struct ddb *dev);

View File

@ -38,7 +38,7 @@
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <linux/dvb/ns.h> #include <linux/dvb/ns.h>
#include "dvbdev.h" #include <media/dvbdev.h>
#define DVBNS_MAXPIDS 32 #define DVBNS_MAXPIDS 32

View File

@ -3,6 +3,32 @@
# DVB device configuration # DVB device configuration
# #
config DVB_MMAP
bool "Enable DVB memory-mapped API (EXPERIMENTAL)"
depends on DVB_CORE
depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE
select VIDEOBUF2_VMALLOC
help
This option enables DVB experimental memory-mapped API, which
reduces the number of context switches to read DVB buffers, as
the buffers can use mmap() syscalls.
Support for it is experimental. Use with care. If unsure,
say N.
config DVB_NET
bool "DVB Network Support"
default (NET && INET)
depends on NET && INET && DVB_CORE
help
This option enables DVB Network Support which is a part of the DVB
standard. It is used, for example, by automatic firmware updates used
on Set-Top-Boxes. It can also be used to access the Internet via the
DVB card, if the network provider supports it.
You may want to disable the network support on embedded devices. If
unsure say Y.
config DVB_MAX_ADAPTERS config DVB_MAX_ADAPTERS
int "maximum number of DVB/ATSC adapters" int "maximum number of DVB/ATSC adapters"
depends on DVB_CORE depends on DVB_CORE
@ -19,7 +45,7 @@ config DVB_MAX_ADAPTERS
config DVB_DYNAMIC_MINORS config DVB_DYNAMIC_MINORS
bool "Dynamic DVB minor allocation" bool "Dynamic DVB minor allocation"
depends on DVB_CORE depends on DVB_CORE
default n default y
help help
If you say Y here, the DVB subsystem will use dynamic minor If you say Y here, the DVB subsystem will use dynamic minor
allocation for any device that uses the DVB major number. allocation for any device that uses the DVB major number.
@ -32,7 +58,6 @@ config DVB_DYNAMIC_MINORS
config DVB_DEMUX_SECTION_LOSS_LOG config DVB_DEMUX_SECTION_LOSS_LOG
bool "Enable DVB demux section packet loss log" bool "Enable DVB demux section packet loss log"
depends on DVB_CORE depends on DVB_CORE
default n
help help
Enable extra log messages meant to detect packet loss Enable extra log messages meant to detect packet loss
inside the Kernel. inside the Kernel.
@ -41,3 +66,15 @@ config DVB_DEMUX_SECTION_LOSS_LOG
be very verbose. be very verbose.
If you are unsure about this, say N here. If you are unsure about this, say N here.
config DVB_ULE_DEBUG
bool "Enable DVB net ULE packet debug messages"
depends on DVB_CORE
help
Enable extra log messages meant to detect problems while
handling DVB network ULE packet loss inside the Kernel.
Should not be enabled on normal cases, as logs can
be very verbose.
If you are unsure about this, say N here.

View File

@ -3,11 +3,14 @@
# Makefile for the kernel DVB device drivers. # Makefile for the kernel DVB device drivers.
# #
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ dvb-net-$(CONFIG_DVB_NET) := dvb_net.o
dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o
dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \
dvb_ca_en50221.o dvb_frontend.o \ dvb_ca_en50221.o dvb_frontend.o \
dvb_net.o dvb_ringbuffer.o dvb_math.o $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) dvb_math.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o obj-$(CONFIG_DVB_CORE) += dvb-core.o
EXTRA_CFLAGS += -DCONFIG_DVB_DYNAMIC_MINORS -DCONFIG_DVB_NET EXTRA_CFLAGS += -DCONFIG_DVB_DYNAMIC_MINORS -DCONFIG_DVB_NET
NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core #NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux

View File

@ -9,3 +9,5 @@ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \
$(dvb-net-y) dvb_ringbuffer.o dvb_math.o $(dvb-net-y) dvb_ringbuffer.o dvb_math.o
obj-$(CONFIG_DVB_CORE) += dvb-core.o obj-$(CONFIG_DVB_CORE) += dvb-core.o
ccflags-y += -Idrivers/media/dvb-core/

View File

@ -18,6 +18,7 @@
#define pr_fmt(fmt) "dmxdev: " fmt #define pr_fmt(fmt) "dmxdev: " fmt
#include <linux/version.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/slab.h> #include <linux/slab.h>
@ -27,8 +28,10 @@
#include <linux/ioctl.h> #include <linux/ioctl.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/version.h> #include <media/dmxdev.h>
#include "dmxdev.h" #ifdef CONFIG_DVB_MMAP
#include <media/dvb_vb2.h>
#endif
static int debug; static int debug;
@ -128,6 +131,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
struct dvb_device *dvbdev = file->private_data; struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv; struct dmxdev *dmxdev = dvbdev->priv;
struct dmx_frontend *front; struct dmx_frontend *front;
bool need_ringbuffer = false;
dprintk("%s\n", __func__); dprintk("%s\n", __func__);
@ -139,14 +143,33 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
return -ENODEV; return -ENODEV;
} }
if ((file->f_flags & O_ACCMODE) == O_RDWR) { dmxdev->may_do_mmap = 0;
/*
* The logic here is a little tricky due to the ifdef.
*
* The ringbuffer is used for both read and mmap.
*
* It is not needed, however, on two situations:
* - Write devices (access with O_WRONLY);
* - For duplex device nodes, opened with O_RDWR.
*/
if ((file->f_flags & O_ACCMODE) == O_RDONLY)
need_ringbuffer = true;
else if ((file->f_flags & O_ACCMODE) == O_RDWR) {
if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) {
#ifdef CONFIG_DVB_MMAP
dmxdev->may_do_mmap = 1;
need_ringbuffer = true;
#else
mutex_unlock(&dmxdev->mutex); mutex_unlock(&dmxdev->mutex);
return -EOPNOTSUPP; return -EOPNOTSUPP;
#endif
} }
} }
if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if (need_ringbuffer) {
void *mem; void *mem;
if (!dvbdev->readers) { if (!dvbdev->readers) {
@ -159,6 +182,11 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
return -ENOMEM; return -ENOMEM;
} }
dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE);
#ifdef CONFIG_DVB_MMAP
if (dmxdev->may_do_mmap)
dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr",
file->f_flags & O_NONBLOCK);
#endif
dvbdev->readers--; dvbdev->readers--;
} }
@ -196,7 +224,15 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
dmxdev->demux->connect_frontend(dmxdev->demux, dmxdev->demux->connect_frontend(dmxdev->demux,
dmxdev->dvr_orig_fe); dmxdev->dvr_orig_fe);
} }
if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
dmxdev->may_do_mmap) {
#ifdef CONFIG_DVB_MMAP
if (dmxdev->may_do_mmap) {
if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx);
dvb_vb2_release(&dmxdev->dvr_vb2_ctx);
}
#endif
dvbdev->readers++; dvbdev->readers++;
if (dmxdev->dvr_buffer.data) { if (dmxdev->dvr_buffer.data) {
void *mem = dmxdev->dvr_buffer.data; void *mem = dmxdev->dvr_buffer.data;
@ -381,12 +417,18 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter)
#endif #endif
static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len, const u8 *buffer2, size_t buffer2_len,
struct dmx_section_filter *filter) struct dmx_section_filter *filter,
u32 *buffer_flags)
{ {
struct dmxdev_filter *dmxdevfilter = filter->priv; struct dmxdev_filter *dmxdevfilter = filter->priv;
int ret; int ret;
#ifdef CONFIG_DVB_MMAP
if (!dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx) &&
dmxdevfilter->buffer.error) {
#else
if (dmxdevfilter->buffer.error) { if (dmxdevfilter->buffer.error) {
#endif
wake_up(&dmxdevfilter->buffer.queue); wake_up(&dmxdevfilter->buffer.queue);
return 0; return 0;
} }
@ -397,12 +439,31 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
} }
del_timer(&dmxdevfilter->timer); del_timer(&dmxdevfilter->timer);
dprintk("section callback %*ph\n", 6, buffer1); dprintk("section callback %*ph\n", 6, buffer1);
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) {
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
buffer1, buffer1_len,
buffer_flags);
if (ret == buffer1_len)
ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx,
buffer2, buffer2_len,
buffer_flags);
} else {
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
buffer1, buffer1_len);
if (ret == buffer1_len) {
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer,
buffer2, buffer2_len);
}
}
#else
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1,
buffer1_len); buffer1_len);
if (ret == buffer1_len) { if (ret == buffer1_len) {
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
buffer2_len); buffer2_len);
} }
#endif
if (ret < 0) if (ret < 0)
dmxdevfilter->buffer.error = ret; dmxdevfilter->buffer.error = ret;
if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
@ -414,7 +475,8 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len, const u8 *buffer2, size_t buffer2_len,
struct dmx_ts_feed *feed) struct dmx_ts_feed *feed,
u32 *buffer_flags)
{ {
struct dmxdev_filter *dmxdevfilter = feed->priv; struct dmxdev_filter *dmxdevfilter = feed->priv;
struct dvb_ringbuffer *buffer; struct dvb_ringbuffer *buffer;
@ -426,19 +488,40 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
return 0; return 0;
} }
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP if (dmxdevfilter->params.pes.output == DMX_OUT_TAP ||
|| dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
buffer = &dmxdevfilter->buffer; buffer = &dmxdevfilter->buffer;
else #ifdef CONFIG_DVB_MMAP
ctx = &dmxdevfilter->vb2_ctx;
#endif
} else {
buffer = &dmxdevfilter->dev->dvr_buffer; buffer = &dmxdevfilter->dev->dvr_buffer;
if (buffer->error) { #ifdef CONFIG_DVB_MMAP
spin_unlock(&dmxdevfilter->dev->lock); ctx = &dmxdevfilter->dev->dvr_vb2_ctx;
wake_up(&buffer->queue); #endif
return 0;
} }
ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
if (ret == buffer1_len) #ifdef CONFIG_DVB_MMAP
ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); if (dvb_vb2_is_streaming(ctx)) {
ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len,
buffer_flags);
if (ret == buffer1_len)
ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len,
buffer_flags);
} else {
#endif
if (buffer->error) {
spin_unlock(&dmxdevfilter->dev->lock);
wake_up(&buffer->queue);
return 0;
}
ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
if (ret == buffer1_len)
ret = dvb_dmxdev_buffer_write(buffer,
buffer2, buffer2_len);
#ifdef CONFIG_DVB_MMAP
}
#endif
if (ret < 0) if (ret < 0)
buffer->error = ret; buffer->error = ret;
spin_unlock(&dmxdevfilter->dev->lock); spin_unlock(&dmxdevfilter->dev->lock);
@ -585,7 +668,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
struct dmxdev_filter *filter, struct dmxdev_filter *filter,
struct dmxdev_feed *feed) struct dmxdev_feed *feed)
{ {
ktime_t timeout; ktime_t timeout = ktime_set(0, 0);
struct dmx_pes_filter_params *para = &filter->params.pes; struct dmx_pes_filter_params *para = &filter->params.pes;
enum dmx_output otype; enum dmx_output otype;
int ret; int ret;
@ -593,7 +676,6 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
enum dmx_ts_pes ts_pes; enum dmx_ts_pes ts_pes;
struct dmx_ts_feed *tsfeed; struct dmx_ts_feed *tsfeed;
timeout = ktime_set(0, 0);
feed->ts = NULL; feed->ts = NULL;
otype = para->output; otype = para->output;
@ -777,7 +859,17 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
mutex_init(&dmxdevfilter->mutex); mutex_init(&dmxdevfilter->mutex);
file->private_data = dmxdevfilter; file->private_data = dmxdevfilter;
#ifdef CONFIG_DVB_MMAP
dmxdev->may_do_mmap = 1;
#else
dmxdev->may_do_mmap = 0;
#endif
dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192);
#ifdef CONFIG_DVB_MMAP
dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter",
file->f_flags & O_NONBLOCK);
#endif
dmxdevfilter->type = DMXDEV_TYPE_NONE; dmxdevfilter->type = DMXDEV_TYPE_NONE;
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0))
@ -797,6 +889,11 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev,
{ {
mutex_lock(&dmxdev->mutex); mutex_lock(&dmxdev->mutex);
mutex_lock(&dmxdevfilter->mutex); mutex_lock(&dmxdevfilter->mutex);
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
dvb_vb2_stream_off(&dmxdevfilter->vb2_ctx);
dvb_vb2_release(&dmxdevfilter->vb2_ctx);
#endif
dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_stop(dmxdevfilter);
dvb_dmxdev_filter_reset(dmxdevfilter); dvb_dmxdev_filter_reset(dmxdevfilter);
@ -1084,8 +1181,56 @@ static int dvb_demux_do_ioctl(struct file *file,
mutex_unlock(&dmxdevfilter->mutex); mutex_unlock(&dmxdevfilter->mutex);
break; break;
#ifdef CONFIG_DVB_MMAP
case DMX_REQBUFS:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_reqbufs(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_QUERYBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_querybuf(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_EXPBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_expbuf(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_QBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_qbuf(&dmxdevfilter->vb2_ctx, parg);
if (ret == 0 && !dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
ret = dvb_vb2_stream_on(&dmxdevfilter->vb2_ctx);
mutex_unlock(&dmxdevfilter->mutex);
break;
case DMX_DQBUF:
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_dqbuf(&dmxdevfilter->vb2_ctx, parg);
mutex_unlock(&dmxdevfilter->mutex);
break;
#endif
default: default:
ret = -EINVAL; ret = -ENOTTY;
break; break;
} }
mutex_unlock(&dmxdev->mutex); mutex_unlock(&dmxdev->mutex);
@ -1098,30 +1243,70 @@ static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
} }
static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0))
typedef unsigned int __poll_t;
#define EPOLLIN POLLIN
#define EPOLLERR POLLERR
#define EPOLLPRI POLLPRI
#define EPOLLRDNORM POLLRDNORM
#define EPOLLWRNORM POLLWRNORM
#define EPOLLOUT POLLOUT
#endif
static __poll_t dvb_demux_poll(struct file *file, poll_table *wait)
{ {
struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev_filter *dmxdevfilter = file->private_data;
unsigned int mask = 0; __poll_t mask = 0;
if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
return POLLERR;
poll_wait(file, &dmxdevfilter->buffer.queue, wait); poll_wait(file, &dmxdevfilter->buffer.queue, wait);
if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
return EPOLLERR;
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx))
return dvb_vb2_poll(&dmxdevfilter->vb2_ctx, file, wait);
#endif
if (dmxdevfilter->state != DMXDEV_STATE_GO && if (dmxdevfilter->state != DMXDEV_STATE_GO &&
dmxdevfilter->state != DMXDEV_STATE_DONE && dmxdevfilter->state != DMXDEV_STATE_DONE &&
dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT) dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
return 0; return 0;
if (dmxdevfilter->buffer.error) if (dmxdevfilter->buffer.error)
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer)) if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
mask |= (POLLIN | POLLRDNORM | POLLPRI); mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
return mask; return mask;
} }
#ifdef CONFIG_DVB_MMAP
static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma)
{
struct dmxdev_filter *dmxdevfilter = file->private_data;
struct dmxdev *dmxdev = dmxdevfilter->dev;
int ret;
if (!dmxdev->may_do_mmap)
return -ENOTTY;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
if (mutex_lock_interruptible(&dmxdevfilter->mutex)) {
mutex_unlock(&dmxdev->mutex);
return -ERESTARTSYS;
}
ret = dvb_vb2_mmap(&dmxdevfilter->vb2_ctx, vma);
mutex_unlock(&dmxdevfilter->mutex);
mutex_unlock(&dmxdev->mutex);
return ret;
}
#endif
static int dvb_demux_release(struct inode *inode, struct file *file) static int dvb_demux_release(struct inode *inode, struct file *file)
{ {
struct dmxdev_filter *dmxdevfilter = file->private_data; struct dmxdev_filter *dmxdevfilter = file->private_data;
@ -1146,10 +1331,14 @@ static const struct file_operations dvb_demux_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = dvb_demux_read, .read = dvb_demux_read,
.unlocked_ioctl = dvb_demux_ioctl, .unlocked_ioctl = dvb_demux_ioctl,
.compat_ioctl = dvb_demux_ioctl,
.open = dvb_demux_open, .open = dvb_demux_open,
.release = dvb_demux_release, .release = dvb_demux_release,
.poll = dvb_demux_poll, .poll = dvb_demux_poll,
.llseek = default_llseek, .llseek = default_llseek,
#ifdef CONFIG_DVB_MMAP
.mmap = dvb_demux_mmap,
#endif
}; };
static const struct dvb_device dvbdev_demux = { static const struct dvb_device dvbdev_demux = {
@ -1178,8 +1367,31 @@ static int dvb_dvr_do_ioctl(struct file *file,
ret = dvb_dvr_set_buffer_size(dmxdev, arg); ret = dvb_dvr_set_buffer_size(dmxdev, arg);
break; break;
#ifdef CONFIG_DVB_MMAP
case DMX_REQBUFS:
ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg);
break;
case DMX_QUERYBUF:
ret = dvb_vb2_querybuf(&dmxdev->dvr_vb2_ctx, parg);
break;
case DMX_EXPBUF:
ret = dvb_vb2_expbuf(&dmxdev->dvr_vb2_ctx, parg);
break;
case DMX_QBUF:
ret = dvb_vb2_qbuf(&dmxdev->dvr_vb2_ctx, parg);
if (ret == 0 && !dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
ret = dvb_vb2_stream_on(&dmxdev->dvr_vb2_ctx);
break;
case DMX_DQBUF:
ret = dvb_vb2_dqbuf(&dmxdev->dvr_vb2_ctx, parg);
break;
#endif
default: default:
ret = -EINVAL; ret = -ENOTTY;
break; break;
} }
mutex_unlock(&dmxdev->mutex); mutex_unlock(&dmxdev->mutex);
@ -1192,31 +1404,58 @@ static long dvb_dvr_ioctl(struct file *file,
return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
} }
static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait)
{ {
struct dvb_device *dvbdev = file->private_data; struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv; struct dmxdev *dmxdev = dvbdev->priv;
unsigned int mask = 0; __poll_t mask = 0;
dprintk("%s\n", __func__); dprintk("%s\n", __func__);
if (dmxdev->exit)
return POLLERR;
poll_wait(file, &dmxdev->dvr_buffer.queue, wait); poll_wait(file, &dmxdev->dvr_buffer.queue, wait);
if ((file->f_flags & O_ACCMODE) == O_RDONLY) { if (dmxdev->exit)
return EPOLLERR;
#ifdef CONFIG_DVB_MMAP
if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx))
return dvb_vb2_poll(&dmxdev->dvr_vb2_ctx, file, wait);
#endif
if (((file->f_flags & O_ACCMODE) == O_RDONLY) ||
dmxdev->may_do_mmap) {
if (dmxdev->dvr_buffer.error) if (dmxdev->dvr_buffer.error)
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
mask |= (POLLIN | POLLRDNORM | POLLPRI); mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
} else } else
mask |= (POLLOUT | POLLWRNORM | POLLPRI); mask |= (EPOLLOUT | EPOLLWRNORM | EPOLLPRI);
return mask; return mask;
} }
#ifdef CONFIG_DVB_MMAP
static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma)
{
struct dvb_device *dvbdev = file->private_data;
struct dmxdev *dmxdev = dvbdev->priv;
int ret;
if (!dmxdev->may_do_mmap)
return -ENOTTY;
if (dmxdev->exit)
return -ENODEV;
if (mutex_lock_interruptible(&dmxdev->mutex))
return -ERESTARTSYS;
ret = dvb_vb2_mmap(&dmxdev->dvr_vb2_ctx, vma);
mutex_unlock(&dmxdev->mutex);
return ret;
}
#endif
static const struct file_operations dvb_dvr_fops = { static const struct file_operations dvb_dvr_fops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.read = dvb_dvr_read, .read = dvb_dvr_read,
@ -1226,6 +1465,9 @@ static const struct file_operations dvb_dvr_fops = {
.release = dvb_dvr_release, .release = dvb_dvr_release,
.poll = dvb_dvr_poll, .poll = dvb_dvr_poll,
.llseek = default_llseek, .llseek = default_llseek,
#ifdef CONFIG_DVB_MMAP
.mmap = dvb_dvr_mmap,
#endif
}; };
static const struct dvb_device dvbdev_dvr = { static const struct dvb_device dvbdev_dvr = {
@ -1237,6 +1479,7 @@ static const struct dvb_device dvbdev_dvr = {
#endif #endif
.fops = &dvb_dvr_fops .fops = &dvb_dvr_fops
}; };
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
{ {
int i; int i;
@ -1244,7 +1487,12 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
if (dmxdev->demux->open(dmxdev->demux) < 0) if (dmxdev->demux->open(dmxdev->demux) < 0)
return -EUSERS; return -EUSERS;
dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter)); #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0))
dmxdev->filter = vmalloc(sizeof(struct dmxdev_filter) * dmxdev->filternum);
#else
dmxdev->filter = vmalloc(array_size(sizeof(struct dmxdev_filter),
dmxdev->filternum));
#endif
if (!dmxdev->filter) if (!dmxdev->filter)
return -ENOMEM; return -ENOMEM;

View File

@ -1,115 +0,0 @@
/*
* dmxdev.h
*
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _DMXDEV_H_
#define _DMXDEV_H_
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/dvb/dmx.h>
#include "dvbdev.h"
#include "demux.h"
#include "dvb_ringbuffer.h"
enum dmxdev_type {
DMXDEV_TYPE_NONE,
DMXDEV_TYPE_SEC,
DMXDEV_TYPE_PES,
};
enum dmxdev_state {
DMXDEV_STATE_FREE,
DMXDEV_STATE_ALLOCATED,
DMXDEV_STATE_SET,
DMXDEV_STATE_GO,
DMXDEV_STATE_DONE,
DMXDEV_STATE_TIMEDOUT
};
struct dmxdev_feed {
u16 pid;
struct dmx_ts_feed *ts;
struct list_head next;
};
struct dmxdev_filter {
union {
struct dmx_section_filter *sec;
} filter;
union {
/* list of TS and PES feeds (struct dmxdev_feed) */
struct list_head ts;
struct dmx_section_feed *sec;
} feed;
union {
struct dmx_sct_filter_params sec;
struct dmx_pes_filter_params pes;
} params;
enum dmxdev_type type;
enum dmxdev_state state;
struct dmxdev *dev;
struct dvb_ringbuffer buffer;
struct mutex mutex;
/* only for sections */
struct timer_list timer;
int todo;
u8 secheader[3];
};
struct dmxdev {
struct dvb_device *dvbdev;
struct dvb_device *dvr_dvbdev;
struct dmxdev_filter *filter;
struct dmx_demux *demux;
int filternum;
int capabilities;
unsigned int exit:1;
#define DMXDEV_CAP_DUPLEX 1
struct dmx_frontend *dvr_orig_fe;
struct dvb_ringbuffer dvr_buffer;
#define DVR_BUFFER_SIZE (10*188*1024)
struct mutex mutex;
spinlock_t lock;
};
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *);
void dvb_dmxdev_release(struct dmxdev *dmxdev);
#endif /* _DMXDEV_H_ */

View File

@ -34,8 +34,8 @@
#endif #endif
#include <linux/kthread.h> #include <linux/kthread.h>
#include "dvb_ca_en50221.h" #include <media/dvb_ca_en50221.h>
#include "dvb_ringbuffer.h" #include <media/dvb_ringbuffer.h>
static int dvb_ca_en50221_debug; static int dvb_ca_en50221_debug;

View File

@ -35,7 +35,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "dvb_demux.h" #include <media/dvb_demux.h>
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
@ -68,6 +68,17 @@ MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
dprintk(x); \ dprintk(x); \
} while (0) } while (0)
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
# define dprintk_sect_loss(x...) dprintk(x)
#else
# define dprintk_sect_loss(x...)
#endif
#define set_buf_flags(__feed, __flag) \
do { \
(__feed)->buffer_flags |= (__flag); \
} while (0)
/****************************************************************************** /******************************************************************************
* static inlined helper functions * static inlined helper functions
******************************************************************************/ ******************************************************************************/
@ -117,30 +128,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
{ {
int count = payload(buf); int count = payload(buf);
int p; int p;
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
int ccok; int ccok;
u8 cc; u8 cc;
#endif
if (count == 0) if (count == 0)
return -1; return -1;
p = 188 - count; p = 188 - count;
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
cc = buf[3] & 0x0f; cc = buf[3] & 0x0f;
ccok = ((feed->cc + 1) & 0x0f) == cc; ccok = ((feed->cc + 1) & 0x0f) == cc;
feed->cc = cc; feed->cc = cc;
if (!ccok) if (!ccok) {
dprintk("missed packet!\n"); set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
#endif dprintk_sect_loss("missed packet: %d instead of %d!\n",
cc, (feed->cc + 1) & 0x0f);
}
if (buf[1] & 0x40) // PUSI ? if (buf[1] & 0x40) // PUSI ?
feed->peslen = 0xfffa; feed->peslen = 0xfffa;
feed->peslen += count; feed->peslen += count;
return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts); return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
} }
static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
@ -162,7 +173,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
return 0; return 0;
return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen,
NULL, 0, &f->filter); NULL, 0, &f->filter, &feed->buffer_flags);
} }
static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
@ -181,8 +192,10 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
if (sec->check_crc) { if (sec->check_crc) {
section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
if (section_syntax_indicator && if (section_syntax_indicator &&
demux->check_crc32(feed, sec->secbuf, sec->seclen)) demux->check_crc32(feed, sec->secbuf, sec->seclen)) {
set_buf_flags(feed, DMX_BUFFER_FLAG_HAD_CRC32_DISCARD);
return -1; return -1;
}
} }
do { do {
@ -199,9 +212,8 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
{ {
struct dmx_section_feed *sec = &feed->feed.sec; struct dmx_section_feed *sec = &feed->feed.sec;
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
if (sec->secbufp < sec->tsfeedp) { if (sec->secbufp < sec->tsfeedp) {
int i, n = sec->tsfeedp - sec->secbufp; int n = sec->tsfeedp - sec->secbufp;
/* /*
* Section padding is done with 0xff bytes entirely. * Section padding is done with 0xff bytes entirely.
@ -209,15 +221,13 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
* but just first and last. * but just first and last.
*/ */
if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) {
dprintk("dvb_demux.c section ts padding loss: %d/%d\n", set_buf_flags(feed,
n, sec->tsfeedp); DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk("dvb_demux.c pad data:"); dprintk_sect_loss("section ts padding loss: %d/%d\n",
for (i = 0; i < n; i++) n, sec->tsfeedp);
pr_cont(" %02x", sec->secbuf[i]); dprintk_sect_loss("pad data: %*ph\n", n, sec->secbuf);
pr_cont("\n");
} }
} }
#endif
sec->tsfeedp = sec->secbufp = sec->seclen = 0; sec->tsfeedp = sec->secbufp = sec->seclen = 0;
sec->secbuf = sec->secbuf_base; sec->secbuf = sec->secbuf_base;
@ -236,10 +246,10 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
* when the second packet arrives. * when the second packet arrives.
* *
* Fix: * Fix:
* when demux is started, let feed->pusi_seen = 0 to * when demux is started, let feed->pusi_seen = false to
* prevent initial feeding of garbage from the end of * prevent initial feeding of garbage from the end of
* previous section. When you for the first time see PUSI=1 * previous section. When you for the first time see PUSI=1
* then set feed->pusi_seen = 1 * then set feed->pusi_seen = true
*/ */
static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
const u8 *buf, u8 len) const u8 *buf, u8 len)
@ -252,11 +262,10 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
return 0; return 0;
if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk("dvb_demux.c section buffer full loss: %d/%d\n", dprintk_sect_loss("section buffer full loss: %d/%d\n",
sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
DMX_MAX_SECFEED_SIZE); DMX_MAX_SECFEED_SIZE);
#endif
len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp;
} }
@ -284,12 +293,13 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
sec->seclen = seclen; sec->seclen = seclen;
sec->crc_val = ~0; sec->crc_val = ~0;
/* dump [secbuf .. secbuf+seclen) */ /* dump [secbuf .. secbuf+seclen) */
if (feed->pusi_seen) if (feed->pusi_seen) {
dvb_dmx_swfilter_section_feed(feed); dvb_dmx_swfilter_section_feed(feed);
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG } else {
else set_buf_flags(feed,
dprintk("dvb_demux.c pusi not seen, discarding section data\n"); DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
#endif dprintk_sect_loss("pusi not seen, discarding section data\n");
}
sec->secbufp += seclen; /* secbufp and secbuf moving together is */ sec->secbufp += seclen; /* secbufp and secbuf moving together is */
sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ sec->secbuf += seclen; /* redundant but saves pointer arithmetic */
} }
@ -322,19 +332,31 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
} }
if (!ccok || dc_i) { if (!ccok || dc_i) {
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG if (dc_i) {
dprintk("dvb_demux.c discontinuity detected %d bytes lost\n", set_buf_flags(feed,
count); DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR);
dprintk_sect_loss("%d frame with disconnect indicator\n",
cc);
} else {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("discontinuity: %d instead of %d. %d bytes lost\n",
cc, (feed->cc + 1) & 0x0f, count + 4);
}
/* /*
* those bytes under sume circumstances will again be reported * those bytes under some circumstances will again be reported
* in the following dvb_dmx_swfilter_section_new * in the following dvb_dmx_swfilter_section_new
*/ */
#endif
/* /*
* Discontinuity detected. Reset pusi_seen = 0 to * Discontinuity detected. Reset pusi_seen to
* stop feeding of suspicious data until next PUSI=1 arrives * stop feeding of suspicious data until next PUSI=1 arrives
*
* FIXME: does it make sense if the MPEG-TS is the one
* reporting discontinuity?
*/ */
feed->pusi_seen = 0;
feed->pusi_seen = false;
dvb_dmx_swfilter_section_new(feed); dvb_dmx_swfilter_section_new(feed);
} }
@ -348,17 +370,16 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
dvb_dmx_swfilter_section_copy_dump(feed, before, dvb_dmx_swfilter_section_copy_dump(feed, before,
before_len); before_len);
/* before start of new section, set pusi_seen = 1 */ /* before start of new section, set pusi_seen */
feed->pusi_seen = 1; feed->pusi_seen = true;
dvb_dmx_swfilter_section_new(feed); dvb_dmx_swfilter_section_new(feed);
dvb_dmx_swfilter_section_copy_dump(feed, after, dvb_dmx_swfilter_section_copy_dump(feed, after,
after_len); after_len);
} else if (count > 0) {
set_buf_flags(feed,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
dprintk_sect_loss("PUSI=1 but %d bytes lost\n", count);
} }
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
else if (count > 0)
dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n",
count);
#endif
} else { } else {
/* PUSI=0 (is not set), no section boundary */ /* PUSI=0 (is not set), no section boundary */
dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count); dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count);
@ -378,8 +399,10 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
if (feed->ts_type & TS_PAYLOAD_ONLY) if (feed->ts_type & TS_PAYLOAD_ONLY)
dvb_dmx_swfilter_payload(feed, buf); dvb_dmx_swfilter_payload(feed, buf);
else else
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
} }
/* Used only on full-featured devices */
if (feed->ts_type & TS_DECODER) if (feed->ts_type & TS_DECODER)
if (feed->demux->write_to_decoder) if (feed->demux->write_to_decoder)
feed->demux->write_to_decoder(feed, buf, 188); feed->demux->write_to_decoder(feed, buf, 188);
@ -426,9 +449,10 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
1024); 1024);
speed_timedelta = ktime_ms_delta(cur_time, speed_timedelta = ktime_ms_delta(cur_time,
demux->speed_last_time); demux->speed_last_time);
dprintk("TS speed %llu Kbits/sec \n", if (speed_timedelta)
div64_u64(speed_bytes, dprintk("TS speed %llu Kbits/sec \n",
speed_timedelta)); div64_u64(speed_bytes,
speed_timedelta));
} }
demux->speed_last_time = cur_time; demux->speed_last_time = cur_time;
@ -437,6 +461,11 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
} }
if (buf[1] & 0x80) { if (buf[1] & 0x80) {
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
set_buf_flags(feed, DMX_BUFFER_FLAG_TEI);
}
dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n", dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n",
pid, buf[1]); pid, buf[1]);
/* data in this packet can't be trusted - drop it unless /* data in this packet can't be trusted - drop it unless
@ -452,6 +481,13 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
(demux->cnt_storage[pid] + 1) & 0xf; (demux->cnt_storage[pid] + 1) & 0xf;
if ((buf[3] & 0xf) != demux->cnt_storage[pid]) { if ((buf[3] & 0xf) != demux->cnt_storage[pid]) {
list_for_each_entry(feed, &demux->feed_list, list_head) {
if ((feed->pid != pid) && (feed->pid != 0x2000))
continue;
set_buf_flags(feed,
DMX_BUFFER_PKT_COUNTER_MISMATCH);
}
dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n", dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n",
pid, demux->cnt_storage[pid], pid, demux->cnt_storage[pid],
buf[3] & 0xf); buf[3] & 0xf);
@ -473,7 +509,8 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
if (feed->pid == pid) if (feed->pid == pid)
dvb_dmx_swfilter_packet_type(feed, buf); dvb_dmx_swfilter_packet_type(feed, buf);
else if (feed->pid == 0x2000) else if (feed->pid == 0x2000)
feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
} }
} }
@ -592,7 +629,16 @@ void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count)
spin_lock_irqsave(&demux->lock, flags); spin_lock_irqsave(&demux->lock, flags);
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts); #if 1
demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts,
&demux->feed->buffer_flags);
#else
struct dvb_demux_feed *feed;
list_for_each_entry(feed, &demux->feed_list, list_head) {
feed->cb.ts(buf, count, NULL, 0, &feed->feed.ts,
&feed->buffer_flags);
}
#endif
spin_unlock_irqrestore(&demux->lock, flags); spin_unlock_irqrestore(&demux->lock, flags);
} }
@ -792,6 +838,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
feed->demux = demux; feed->demux = demux;
feed->pid = 0xffff; feed->pid = 0xffff;
feed->peslen = 0xfffa; feed->peslen = 0xfffa;
feed->buffer_flags = 0;
(*ts_feed) = &feed->feed.ts; (*ts_feed) = &feed->feed.ts;
(*ts_feed)->parent = dmx; (*ts_feed)->parent = dmx;
@ -911,14 +958,14 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
return; return;
do { do {
sf = &f->filter; sf = &f->filter;
doneq = 0; doneq = false;
for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
mode = sf->filter_mode[i]; mode = sf->filter_mode[i];
mask = sf->filter_mask[i]; mask = sf->filter_mask[i];
f->maskandmode[i] = mask & mode; f->maskandmode[i] = mask & mode;
doneq |= f->maskandnotmode[i] = mask & ~mode; doneq |= f->maskandnotmode[i] = mask & ~mode;
} }
f->doneq = doneq ? 1 : 0; f->doneq = doneq ? true : false;
} while ((f = f->next)); } while ((f = f->next));
} }
@ -945,6 +992,7 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed)
dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
dvbdmxfeed->feed.sec.secbufp = 0; dvbdmxfeed->feed.sec.secbufp = 0;
dvbdmxfeed->feed.sec.seclen = 0; dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->pusi_seen = false;
if (!dvbdmx->start_feed) { if (!dvbdmx->start_feed) {
mutex_unlock(&dvbdmx->mutex); mutex_unlock(&dvbdmx->mutex);
@ -1049,6 +1097,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
dvbdmxfeed->cb.sec = callback; dvbdmxfeed->cb.sec = callback;
dvbdmxfeed->demux = dvbdmx; dvbdmxfeed->demux = dvbdmx;
dvbdmxfeed->pid = 0xffff; dvbdmxfeed->pid = 0xffff;
dvbdmxfeed->buffer_flags = 0;
dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
dvbdmxfeed->feed.sec.tsfeedp = 0; dvbdmxfeed->feed.sec.tsfeedp = 0;
@ -1220,12 +1269,25 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
dvbdemux->cnt_storage = NULL; dvbdemux->cnt_storage = NULL;
dvbdemux->users = 0; dvbdemux->users = 0;
dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0))
dvbdemux->filter = vmalloc(sizeof(struct dvb_demux_filter) *
dvbdemux->filternum);
if (!dvbdemux->filter) if (!dvbdemux->filter)
return -ENOMEM; return -ENOMEM;
dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed)); dvbdemux->feed = vmalloc(sizeof(struct dvb_demux_feed) *
dvbdemux->feednum);
#else
dvbdemux->filter = vmalloc(array_size(sizeof(struct dvb_demux_filter),
dvbdemux->filternum));
if (!dvbdemux->filter)
return -ENOMEM;
dvbdemux->feed = vmalloc(array_size(sizeof(struct dvb_demux_feed),
dvbdemux->feednum));
#endif
if (!dvbdemux->feed) { if (!dvbdemux->feed) {
vfree(dvbdemux->filter); vfree(dvbdemux->filter);
dvbdemux->filter = NULL; dvbdemux->filter = NULL;

View File

@ -1,145 +0,0 @@
/*
* dvb_demux.h: DVB kernel demux API
*
* Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _DVB_DEMUX_H_
#define _DVB_DEMUX_H_
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include "demux.h"
#define DMX_TYPE_TS 0
#define DMX_TYPE_SEC 1
#define DMX_TYPE_PES 2
#define DMX_STATE_FREE 0
#define DMX_STATE_ALLOCATED 1
#define DMX_STATE_SET 2
#define DMX_STATE_READY 3
#define DMX_STATE_GO 4
#define DVB_DEMUX_MASK_MAX 18
#define MAX_PID 0x1fff
#define SPEED_PKTS_INTERVAL 50000
struct dvb_demux_filter {
struct dmx_section_filter filter;
u8 maskandmode[DMX_MAX_FILTER_SIZE];
u8 maskandnotmode[DMX_MAX_FILTER_SIZE];
int doneq;
struct dvb_demux_filter *next;
struct dvb_demux_feed *feed;
int index;
int state;
int type;
u16 hw_handle;
struct timer_list timer;
};
#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head)
struct dvb_demux_feed {
union {
struct dmx_ts_feed ts;
struct dmx_section_feed sec;
} feed;
union {
dmx_ts_cb ts;
dmx_section_cb sec;
} cb;
struct dvb_demux *demux;
void *priv;
int type;
int state;
u16 pid;
ktime_t timeout;
struct dvb_demux_filter *filter;
int ts_type;
enum dmx_ts_pes pes_type;
int cc;
int pusi_seen; /* prevents feeding of garbage from previous section */
u16 peslen;
struct list_head list_head;
unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */
};
struct dvb_demux {
struct dmx_demux dmx;
void *priv;
int filternum;
int feednum;
int (*start_feed)(struct dvb_demux_feed *feed);
int (*stop_feed)(struct dvb_demux_feed *feed);
int (*write_to_decoder)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
u32 (*check_crc32)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
const u8 *src, size_t len);
int users;
#define MAX_DVB_DEMUX_USERS 10
struct dvb_demux_filter *filter;
struct dvb_demux_feed *feed;
struct list_head frontend_list;
struct dvb_demux_feed *pesfilter[DMX_PES_OTHER];
u16 pids[DMX_PES_OTHER];
int playing;
int recording;
#define DMX_MAX_PID 0x2000
struct list_head feed_list;
u8 tsbuf[204];
int tsbufp;
struct mutex mutex;
spinlock_t lock;
uint8_t *cnt_storage; /* for TS continuity check */
ktime_t speed_last_time; /* for TS speed check */
uint32_t speed_pkts_cnt; /* for TS speed check */
};
int dvb_dmx_init(struct dvb_demux *dvbdemux);
void dvb_dmx_release(struct dvb_demux *dvbdemux);
void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf,
size_t count);
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
size_t count);
void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
size_t count);
#endif /* _DVB_DEMUX_H_ */

File diff suppressed because it is too large Load Diff

View File

@ -19,7 +19,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/module.h> #include <linux/module.h>
#include <asm/bug.h> #include <asm/bug.h>
#include "dvb_math.h" #include <media/dvb_math.h>
static const unsigned short logtable[256] = { static const unsigned short logtable[256] = {
0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* dvb_net.c * dvb_net.c
* *
@ -13,18 +14,6 @@
* and Wolfram Stering <wstering@cosy.sbg.ac.at> * and Wolfram Stering <wstering@cosy.sbg.ac.at>
* *
* ULE Decaps according to RFC 4326. * ULE Decaps according to RFC 4326.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* To obtain the license, point your browser to
* http://www.gnu.org/copyleft/gpl.html
*/ */
/* /*
@ -38,7 +27,7 @@
* Competence Center for Advanced Satellite Communications. * Competence Center for Advanced Satellite Communications.
* Bugfixes and robustness improvements. * Bugfixes and robustness improvements.
* Filtering on dest MAC addresses, if present (D-Bit = 0) * Filtering on dest MAC addresses, if present (D-Bit = 0)
* ULE_DEBUG compile-time option. * DVB_ULE_DEBUG compile-time option.
* Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by * Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by
* Christian Praehauser <cpraehaus@cosy.sbg.ac.at>, * Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
* Paris Lodron University of Salzburg. * Paris Lodron University of Salzburg.
@ -69,8 +58,8 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/sched.h> #include <linux/sched.h>
#include "dvb_demux.h" #include <media/dvb_demux.h>
#include "dvb_net.h" #include <media/dvb_net.h>
static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt ) static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
{ {
@ -83,15 +72,20 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt )
#define DVB_NET_MULTICAST_MAX 10 #define DVB_NET_MULTICAST_MAX 10
#undef ULE_DEBUG #undef DVB_ULE_DEBUG
#ifdef ULE_DEBUG #ifdef DVB_ULE_DEBUG
/*
* The code inside DVB_ULE_DEBUG keeps a history of the
* last 100 TS cells processed.
*/
static unsigned char ule_hist[100*TS_SZ] = { 0 };
static unsigned char *ule_where = ule_hist, ule_dump;
static void hexdump(const unsigned char *buf, unsigned short len) static void hexdump(const unsigned char *buf, unsigned short len)
{ {
print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true); print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true);
} }
#endif #endif
struct dvb_net_priv { struct dvb_net_priv {
@ -130,7 +124,7 @@ struct dvb_net_priv {
}; };
/** /*
* Determine the packet's protocol ID. The rule here is that we * Determine the packet's protocol ID. The rule here is that we
* assume 802.3 if the type field is short enough to be a length. * assume 802.3 if the type field is short enough to be a length.
* This is normal practice and works for any 'now in use' protocol. * This is normal practice and works for any 'now in use' protocol.
@ -160,7 +154,7 @@ static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
rawp = skb->data; rawp = skb->data;
/** /*
* This is a magic hack to spot IPX packets. Older Novell breaks * This is a magic hack to spot IPX packets. Older Novell breaks
* the protocol design and runs IPX over 802.3 without an 802.2 LLC * the protocol design and runs IPX over 802.3 without an 802.2 LLC
* layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This
@ -169,7 +163,7 @@ static __be16 dvb_net_eth_type_trans(struct sk_buff *skb,
if (*(unsigned short *)rawp == 0xFFFF) if (*(unsigned short *)rawp == 0xFFFF)
return htons(ETH_P_802_3); return htons(ETH_P_802_3);
/** /*
* Real 802.2 LLC * Real 802.2 LLC
*/ */
return htons(ETH_P_802_2); return htons(ETH_P_802_2);
@ -220,7 +214,8 @@ static int ule_exthdr_padding(struct dvb_net_priv *p)
return 0; return 0;
} }
/** Handle ULE extension headers. /*
* Handle ULE extension headers.
* Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding. * Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding.
* Returns: >= 0: nr. of bytes consumed by next extension header * Returns: >= 0: nr. of bytes consumed by next extension header
* -1: Mandatory extension header that is not recognized or TEST SNDU; discard. * -1: Mandatory extension header that is not recognized or TEST SNDU; discard.
@ -284,11 +279,9 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
if (l < 0) if (l < 0)
return l; /* Stop extension header processing and discard SNDU. */ return l; /* Stop extension header processing and discard SNDU. */
total_ext_len += l; total_ext_len += l;
#ifdef ULE_DEBUG
pr_debug("ule_next_hdr=%p, ule_sndu_type=%i, l=%i, total_ext_len=%i\n", pr_debug("ule_next_hdr=%p, ule_sndu_type=%i, l=%i, total_ext_len=%i\n",
p->ule_next_hdr, (int)p->ule_sndu_type, p->ule_next_hdr, (int)p->ule_sndu_type,
l, total_ext_len); l, total_ext_len);
#endif
} while (p->ule_sndu_type < ETH_P_802_3_MIN); } while (p->ule_sndu_type < ETH_P_802_3_MIN);
@ -296,7 +289,7 @@ static int handle_ule_extensions( struct dvb_net_priv *p )
} }
/** Prepare for a new ULE SNDU: reset the decoder state. */ /* Prepare for a new ULE SNDU: reset the decoder state. */
static inline void reset_ule( struct dvb_net_priv *p ) static inline void reset_ule( struct dvb_net_priv *p )
{ {
p->ule_skb = NULL; p->ule_skb = NULL;
@ -309,7 +302,7 @@ static inline void reset_ule( struct dvb_net_priv *p )
p->ule_bridged = 0; p->ule_bridged = 0;
} }
/** /*
* Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of
* TS cells of a single PID. * TS cells of a single PID.
*/ */
@ -324,29 +317,21 @@ struct dvb_net_ule_handle {
const u8 *ts, *ts_end, *from_where; const u8 *ts, *ts_end, *from_where;
u8 ts_remain, how_much, new_ts; u8 ts_remain, how_much, new_ts;
bool error; bool error;
#ifdef ULE_DEBUG
/*
* The code inside ULE_DEBUG keeps a history of the
* last 100 TS cells processed.
*/
static unsigned char ule_hist[100*TS_SZ];
static unsigned char *ule_where = ule_hist, ule_dump;
#endif
}; };
static int dvb_net_ule_new_ts_cell(struct dvb_net_ule_handle *h) static int dvb_net_ule_new_ts_cell(struct dvb_net_ule_handle *h)
{ {
/* We are about to process a new TS cell. */ /* We are about to process a new TS cell. */
#ifdef ULE_DEBUG #ifdef DVB_ULE_DEBUG
if (h->ule_where >= &h->ule_hist[100*TS_SZ]) if (ule_where >= &ule_hist[100*TS_SZ])
h->ule_where = h->ule_hist; ule_where = ule_hist;
memcpy(h->ule_where, h->ts, TS_SZ); memcpy(ule_where, h->ts, TS_SZ);
if (h->ule_dump) { if (ule_dump) {
hexdump(h->ule_where, TS_SZ); hexdump(ule_where, TS_SZ);
h->ule_dump = 0; ule_dump = 0;
} }
h->ule_where += TS_SZ; ule_where += TS_SZ;
#endif #endif
/* /*
@ -664,6 +649,7 @@ static int dvb_net_ule_should_drop(struct dvb_net_ule_handle *h)
static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h, static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
struct kvec iov[3],
u32 ule_crc, u32 expected_crc) u32 ule_crc, u32 expected_crc)
{ {
u8 dest_addr[ETH_ALEN]; u8 dest_addr[ETH_ALEN];
@ -676,22 +662,22 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
h->ts_remain > 2 ? h->ts_remain > 2 ?
*(unsigned short *)h->from_where : 0); *(unsigned short *)h->from_where : 0);
#ifdef ULE_DEBUG #ifdef DVB_ULE_DEBUG
hexdump(iov[0].iov_base, iov[0].iov_len); hexdump(iov[0].iov_base, iov[0].iov_len);
hexdump(iov[1].iov_base, iov[1].iov_len); hexdump(iov[1].iov_base, iov[1].iov_len);
hexdump(iov[2].iov_base, iov[2].iov_len); hexdump(iov[2].iov_base, iov[2].iov_len);
if (h->ule_where == h->ule_hist) { if (ule_where == ule_hist) {
hexdump(&h->ule_hist[98*TS_SZ], TS_SZ); hexdump(&ule_hist[98*TS_SZ], TS_SZ);
hexdump(&h->ule_hist[99*TS_SZ], TS_SZ); hexdump(&ule_hist[99*TS_SZ], TS_SZ);
} else if (h->ule_where == &h->ule_hist[TS_SZ]) { } else if (ule_where == &ule_hist[TS_SZ]) {
hexdump(&h->ule_hist[99*TS_SZ], TS_SZ); hexdump(&ule_hist[99*TS_SZ], TS_SZ);
hexdump(h->ule_hist, TS_SZ); hexdump(ule_hist, TS_SZ);
} else { } else {
hexdump(h->ule_where - TS_SZ - TS_SZ, TS_SZ); hexdump(ule_where - TS_SZ - TS_SZ, TS_SZ);
hexdump(h->ule_where - TS_SZ, TS_SZ); hexdump(ule_where - TS_SZ, TS_SZ);
} }
h->ule_dump = 1; ule_dump = 1;
#endif #endif
h->dev->stats.rx_errors++; h->dev->stats.rx_errors++;
@ -709,11 +695,9 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h,
if (!h->priv->ule_dbit) { if (!h->priv->ule_dbit) {
if (dvb_net_ule_should_drop(h)) { if (dvb_net_ule_should_drop(h)) {
#ifdef ULE_DEBUG
netdev_dbg(h->dev, netdev_dbg(h->dev,
"Dropping SNDU: MAC destination address does not match: dest addr: %pM, h->dev addr: %pM\n", "Dropping SNDU: MAC destination address does not match: dest addr: %pM, h->dev addr: %pM\n",
h->priv->ule_skb->data, h->dev->dev_addr); h->priv->ule_skb->data, h->dev->dev_addr);
#endif
dev_kfree_skb(h->priv->ule_skb); dev_kfree_skb(h->priv->ule_skb);
return; return;
} }
@ -784,6 +768,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
struct dvb_net_ule_handle h = { struct dvb_net_ule_handle h = {
.dev = dev, .dev = dev,
.priv = netdev_priv(dev), .priv = netdev_priv(dev),
.ethh = NULL,
.buf = buf, .buf = buf,
.buf_len = buf_len, .buf_len = buf_len,
.skipped = 0L, .skipped = 0L,
@ -793,11 +778,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
.ts_remain = 0, .ts_remain = 0,
.how_much = 0, .how_much = 0,
.new_ts = 1, .new_ts = 1,
.ethh = NULL,
.error = false, .error = false,
#ifdef ULE_DEBUG
.ule_where = ule_hist,
#endif
}; };
/* /*
@ -869,7 +850,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
*(tail - 2) << 8 | *(tail - 2) << 8 |
*(tail - 1); *(tail - 1);
dvb_net_ule_check_crc(&h, ule_crc, expected_crc); dvb_net_ule_check_crc(&h, iov, ule_crc, expected_crc);
/* Prepare for next SNDU. */ /* Prepare for next SNDU. */
reset_ule(h.priv); reset_ule(h.priv);
@ -902,7 +883,8 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len)
static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len, const u8 *buffer2, size_t buffer2_len,
struct dmx_ts_feed *feed) struct dmx_ts_feed *feed,
u32 *buffer_flags)
{ {
struct net_device *dev = feed->priv; struct net_device *dev = feed->priv;
@ -1010,12 +992,12 @@ static void dvb_net_sec(struct net_device *dev,
} }
static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
const u8 *buffer2, size_t buffer2_len, const u8 *buffer2, size_t buffer2_len,
struct dmx_section_filter *filter) struct dmx_section_filter *filter, u32 *buffer_flags)
{ {
struct net_device *dev = filter->priv; struct net_device *dev = filter->priv;
/** /*
* we rely on the DVB API definition where exactly one complete * we rely on the DVB API definition where exactly one complete
* section is delivered in buffer1 * section is delivered in buffer1
*/ */
@ -1023,7 +1005,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
return 0; return 0;
} }
static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev) static netdev_tx_t dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
{ {
dev_kfree_skb(skb); dev_kfree_skb(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;

View File

@ -34,7 +34,7 @@
#include <linux/uaccess.h> #include <linux/uaccess.h>
#endif #endif
#include "dvb_ringbuffer.h" #include <media/dvb_ringbuffer.h>
#define PKT_READY 0 #define PKT_READY 0
#define PKT_DISPOSED 1 #define PKT_DISPOSED 1
@ -63,7 +63,7 @@ int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf)
* this pairs with smp_store_release() in dvb_ringbuffer_write(), * this pairs with smp_store_release() in dvb_ringbuffer_write(),
* dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset() * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset()
* *
* for memory barriers also see Documentation/circular-buffers.txt * for memory barriers also see Documentation/core-api/circular-buffers.txt
*/ */
return (rbuf->pread == smp_load_acquire(&rbuf->pwrite)); return (rbuf->pread == smp_load_acquire(&rbuf->pwrite));
#endif #endif

View File

@ -24,6 +24,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/device.h> #include <linux/device.h>
@ -31,7 +32,7 @@
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/version.h> #include <linux/version.h>
#include "dvbdev.h" #include <media/dvbdev.h>
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0)) #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0))
/* Due to enum tuner_pad_index */ /* Due to enum tuner_pad_index */
@ -54,8 +55,19 @@ static LIST_HEAD(dvb_adapter_list);
static DEFINE_MUTEX(dvbdev_register_lock); static DEFINE_MUTEX(dvbdev_register_lock);
static const char * const dnames[] = { static const char * const dnames[] = {
"video", "audio", "sec", "frontend", "demux", "dvr", "ca", [DVB_DEVICE_VIDEO] = "video",
"net", "osd", "ci", "mod", "ns", "nsd" [DVB_DEVICE_AUDIO] = "audio",
[DVB_DEVICE_SEC] = "sec",
[DVB_DEVICE_FRONTEND] = "frontend",
[DVB_DEVICE_DEMUX] = "demux",
[DVB_DEVICE_DVR] = "dvr",
[DVB_DEVICE_CA] = "ca",
[DVB_DEVICE_NET] = "net",
[DVB_DEVICE_OSD] = "osd",
[DVB_DEVICE_CI] = "ci",
[DVB_DEVICE_MOD] = "mod",
[DVB_DEVICE_NS] = "ns",
[DVB_DEVICE_NSD] = "nsd",
}; };
#ifdef CONFIG_DVB_DYNAMIC_MINORS #ifdef CONFIG_DVB_DYNAMIC_MINORS
@ -63,7 +75,22 @@ static const char * const dnames[] = {
#define DVB_MAX_IDS MAX_DVB_MINORS #define DVB_MAX_IDS MAX_DVB_MINORS
#else #else
#define DVB_MAX_IDS 4 #define DVB_MAX_IDS 4
#define nums2minor(num, type, id) ((num << 6) | (id << 4) | type)
static const u8 minor_type[] = {
[DVB_DEVICE_VIDEO] = 0,
[DVB_DEVICE_AUDIO] = 1,
[DVB_DEVICE_SEC] = 2,
[DVB_DEVICE_FRONTEND] = 3,
[DVB_DEVICE_DEMUX] = 4,
[DVB_DEVICE_DVR] = 5,
[DVB_DEVICE_CA] = 6,
[DVB_DEVICE_NET] = 7,
[DVB_DEVICE_OSD] = 8,
};
#define nums2minor(num, type, id) \
(((num) << 6) | ((id) << 4) | minor_type[type])
#define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64)
#endif #endif
@ -319,8 +346,10 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
if (npads) { if (npads) {
dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads), dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
GFP_KERNEL); GFP_KERNEL);
if (!dvbdev->pads) if (!dvbdev->pads){
kfree(dvbdev->entity);
return -ENOMEM; return -ENOMEM;
}
} }
switch (type) { switch (type) {
@ -420,8 +449,10 @@ static int dvb_register_media_device(struct dvb_device *dvbdev,
if (!dvbdev->entity) if (!dvbdev->entity)
return 0; return 0;
link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf, link = media_create_intf_link(dvbdev->entity,
MEDIA_LNK_FL_ENABLED); &dvbdev->intf_devnode->intf,
MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link) if (!link)
return -ENOMEM; return -ENOMEM;
#endif #endif
@ -429,8 +460,8 @@ static int dvb_register_media_device(struct dvb_device *dvbdev,
} }
int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
const struct dvb_device *template, void *priv, int type, const struct dvb_device *template, void *priv,
int demux_sink_pads) enum dvb_device_type type, int demux_sink_pads)
{ {
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
struct file_operations *dvbdevfops; struct file_operations *dvbdevfops;
@ -454,7 +485,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
return -ENOMEM; return -ENOMEM;
} }
dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
if (!dvbdevfops){ if (!dvbdevfops){
kfree (dvbdev); kfree (dvbdev);
@ -470,7 +501,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvbdev->fops = dvbdevfops; dvbdev->fops = dvbdevfops;
init_waitqueue_head (&dvbdev->wait_queue); init_waitqueue_head (&dvbdev->wait_queue);
memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
dvbdevfops->owner = adap->module; dvbdevfops->owner = adap->module;
list_add_tail (&dvbdev->list_head, &adap->device_list); list_add_tail (&dvbdev->list_head, &adap->device_list);
@ -504,7 +534,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
dvb_media_device_free(dvbdev); dvb_media_device_free(dvbdev);
kfree(dvbdevfops); kfree(dvbdevfops);
kfree(dvbdev); kfree(dvbdev);
up_write(&minor_rwsem);
mutex_unlock(&dvbdev_register_lock); mutex_unlock(&dvbdev_register_lock);
return ret; return ret;
} }
@ -579,7 +608,8 @@ static int dvb_create_io_intf_links(struct dvb_adapter *adap,
if (strncmp(entity->name, name, strlen(name))) if (strncmp(entity->name, name, strlen(name)))
continue; continue;
link = media_create_intf_link(entity, intf, link = media_create_intf_link(entity, intf,
MEDIA_LNK_FL_ENABLED); MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link) if (!link)
return -ENOMEM; return -ENOMEM;
} }
@ -598,8 +628,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
unsigned demux_pad = 0; unsigned demux_pad = 0;
unsigned dvr_pad = 0; unsigned dvr_pad = 0;
unsigned ntuner = 0, ndemod = 0; unsigned ntuner = 0, ndemod = 0;
u16 source_pad = 0; int ret, pad_source, pad_sink;
int ret;
static const char *connector_name = "Television"; static const char *connector_name = "Television";
if (!mdev) if (!mdev)
@ -660,17 +689,6 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
return ret; return ret;
if (!ntuner) { if (!ntuner) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
if ((ret = media_get_pad_index(tuner, true,
PAD_SIGNAL_ANALOG)) < 0)
return ret;
source_pad = (u16) ret;
ret = 0;
#else
source_pad = TUNER_PAD_RF_INPUT;
#endif
ret = media_create_pad_links(mdev, ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF, MEDIA_ENT_F_CONN_RF,
conn, 0, conn, 0,
@ -679,32 +697,40 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
MEDIA_LNK_FL_ENABLED, MEDIA_LNK_FL_ENABLED,
false); false);
} else { } else {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
pad_sink = media_get_pad_index(tuner, true,
PAD_SIGNAL_ANALOG);
if (pad_sink < 0)
return -EINVAL;
ret = media_create_pad_links(mdev, ret = media_create_pad_links(mdev,
MEDIA_ENT_F_CONN_RF, MEDIA_ENT_F_CONN_RF,
conn, 0, conn, 0,
MEDIA_ENT_F_TUNER, MEDIA_ENT_F_TUNER,
tuner, source_pad, tuner, pad_sink,
MEDIA_LNK_FL_ENABLED, MEDIA_LNK_FL_ENABLED,
false); false);
#else
pad_sink = TUNER_PAD_RF_INPUT;
#endif
} }
if (ret) if (ret)
return ret; return ret;
} }
if (ntuner && ndemod) { if (ntuner && ndemod) {
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0))
if ((ret = media_get_pad_index(tuner, true, PAD_SIGNAL_ANALOG)) < 0) /* NOTE: first found tuner source pad presumed correct */
return ret; pad_source = media_get_pad_index(tuner, false,
source_pad = (u16) ret; PAD_SIGNAL_ANALOG);
ret = 0; if (pad_source < 0)
return -EINVAL;
#else #else
source_pad = TUNER_PAD_OUTPUT; pad_source = TUNER_PAD_OUTPUT;
#endif #endif
ret = media_create_pad_links(mdev, ret = media_create_pad_links(mdev,
MEDIA_ENT_F_TUNER, MEDIA_ENT_F_TUNER,
tuner, source_pad, tuner, pad_source,
MEDIA_ENT_F_DTV_DEMOD, MEDIA_ENT_F_DTV_DEMOD,
demod, 0, MEDIA_LNK_FL_ENABLED, demod, 0, MEDIA_LNK_FL_ENABLED,
false); false);
@ -757,14 +783,16 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
media_device_for_each_intf(intf, mdev) { media_device_for_each_intf(intf, mdev) {
if (intf->type == MEDIA_INTF_T_DVB_CA && ca) { if (intf->type == MEDIA_INTF_T_DVB_CA && ca) {
link = media_create_intf_link(ca, intf, link = media_create_intf_link(ca, intf,
MEDIA_LNK_FL_ENABLED); MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link) if (!link)
return -ENOMEM; return -ENOMEM;
} }
if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) { if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
link = media_create_intf_link(tuner, intf, link = media_create_intf_link(tuner, intf,
MEDIA_LNK_FL_ENABLED); MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link) if (!link)
return -ENOMEM; return -ENOMEM;
} }
@ -776,7 +804,8 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
*/ */
if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) { if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
link = media_create_intf_link(demux, intf, link = media_create_intf_link(demux, intf,
MEDIA_LNK_FL_ENABLED); MEDIA_LNK_FL_ENABLED |
MEDIA_LNK_FL_IMMUTABLE);
if (!link) if (!link)
return -ENOMEM; return -ENOMEM;
} }
@ -862,6 +891,10 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
adap->mfe_dvbdev = NULL; adap->mfe_dvbdev = NULL;
mutex_init (&adap->mfe_lock); mutex_init (&adap->mfe_lock);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB
mutex_init(&adap->mdev_lock);
#endif
list_add_tail (&adap->list_head, &dvb_adapter_list); list_add_tail (&adap->list_head, &dvb_adapter_list);
mutex_unlock(&dvbdev_register_lock); mutex_unlock(&dvbdev_register_lock);
@ -882,7 +915,7 @@ EXPORT_SYMBOL(dvb_unregister_adapter);
/* if the miracle happens and "generic_usercopy()" is included into /* if the miracle happens and "generic_usercopy()" is included into
the kernel, then this can vanish. please don't make the mistake and the kernel, then this can vanish. please don't make the mistake and
define this as video_usercopy(). this will introduce a dependecy define this as video_usercopy(). this will introduce a dependency
to the v4l "videodev.o" module, which is unnecessary for some to the v4l "videodev.o" module, which is unnecessary for some
cards (ie. the budget dvb-cards don't need the v4l module...) */ cards (ie. the budget dvb-cards don't need the v4l module...) */
int dvb_usercopy(struct file *file, int dvb_usercopy(struct file *file,
@ -946,6 +979,57 @@ out:
} }
EXPORT_SYMBOL(dvb_usercopy); EXPORT_SYMBOL(dvb_usercopy);
#if IS_ENABLED(CONFIG_I2C)
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0))
struct i2c_client *dvb_module_probe(const char *module_name,
const char *name,
struct i2c_adapter *adap,
unsigned char addr,
void *platform_data)
{
struct i2c_client *client;
struct i2c_board_info *board_info;
board_info = kzalloc(sizeof(*board_info), GFP_KERNEL);
if (!board_info)
return NULL;
if (name)
strscpy(board_info->type, name, I2C_NAME_SIZE);
else
strscpy(board_info->type, module_name, I2C_NAME_SIZE);
board_info->addr = addr;
board_info->platform_data = platform_data;
request_module(module_name);
client = i2c_new_client_device(adap, board_info);
if (!i2c_client_has_driver(client)) {
kfree(board_info);
return NULL;
}
if (!try_module_get(client->dev.driver->owner)) {
i2c_unregister_device(client);
client = NULL;
}
kfree(board_info);
return client;
}
EXPORT_SYMBOL_GPL(dvb_module_probe);
void dvb_module_release(struct i2c_client *client)
{
if (!client)
return;
module_put(client->dev.driver->owner);
i2c_unregister_device(client);
}
EXPORT_SYMBOL_GPL(dvb_module_release);
#endif
#endif
static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env)
{ {
struct dvb_device *dvbdev = dev_get_drvdata(dev); struct dvb_device *dvbdev = dev_get_drvdata(dev);

View File

@ -16,7 +16,6 @@ EXTRA_CFLAGS += -DCONFIG_DVB_LNBH25
EXTRA_CFLAGS += -DCONFIG_DVB_MXL5XX EXTRA_CFLAGS += -DCONFIG_DVB_MXL5XX
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2099 EXTRA_CFLAGS += -DCONFIG_DVB_CXD2099
EXTRA_CFLAGS += -DDBVALS EXTRA_CFLAGS += -DDBVALS
NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core
drxk-objs := drxk_hard.o drxk-objs := drxk_hard.o
obj-$(CONFIG_DVB_DRXK) += drxk.o obj-$(CONFIG_DVB_DRXK) += drxk.o

View File

@ -25,7 +25,7 @@
#ifndef _CXD2099_H_ #ifndef _CXD2099_H_
#define _CXD2099_H_ #define _CXD2099_H_
#include <dvb_ca_en50221.h> #include <media/dvb_ca_en50221.h>
struct cxd2099_cfg { struct cxd2099_cfg {
u32 bitrate; u32 bitrate;

View File

@ -35,8 +35,8 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "dvb_math.h" #include <media/dvb_math.h>
#include "cxd2843.h" #include "cxd2843.h"
#define Log10x100(x) ((s32)(((((u64) intlog2(x) * 0x1e1a5e2e) >> 47 ) + 1) >> 1)) #define Log10x100(x) ((s32)(((((u64) intlog2(x) * 0x1e1a5e2e) >> 47 ) + 1) >> 1))
@ -105,8 +105,12 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len)
static int writeregs(struct cxd_state *state, u8 adr, u8 reg, static int writeregs(struct cxd_state *state, u8 adr, u8 reg,
u8 *regd, u16 len) u8 *regd, u16 len)
{ {
u8 data[len + 1]; u8 data[16];
if (len >= 15) {
pr_err("cxd2843: writeregs length %u too large\n", len);
return -1;
}
data[0] = reg; data[0] = reg;
memcpy(data + 1, regd, len); memcpy(data + 1, regd, len);
return i2c_write(state->i2c, adr, data, len + 1); return i2c_write(state->i2c, adr, data, len + 1);
@ -2240,7 +2244,7 @@ static enum dvbfe_search search(struct dvb_frontend *fe)
return DVBFE_ALGO_SEARCH_AGAIN; return DVBFE_ALGO_SEARCH_AGAIN;
} }
static int get_algo(struct dvb_frontend *fe) static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{ {
return DVBFE_ALGO_HW; return DVBFE_ALGO_HW;
} }
@ -2489,9 +2493,9 @@ static struct dvb_frontend_ops common_ops_2854 = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2, SYS_ISDBT }, .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2, SYS_ISDBT },
.info = { .info = {
.name = "CXD2854 DVB-C/C2 DVB-T/T2 ISDB-T", .name = "CXD2854 DVB-C/C2 DVB-T/T2 ISDB-T",
.frequency_stepsize = 166667, /* DVB-T only */ .frequency_stepsize_hz = 166667, /* DVB-T only */
.frequency_min = 47000000, /* DVB-T: 47125000 */ .frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */ .frequency_max_hz = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 870000, .symbol_rate_min = 870000,
.symbol_rate_max = 11700000, .symbol_rate_max = 11700000,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
@ -2523,9 +2527,9 @@ static struct dvb_frontend_ops common_ops_2843 = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2 }, .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2 },
.info = { .info = {
.name = "CXD2843 DVB-C/C2 DVB-T/T2", .name = "CXD2843 DVB-C/C2 DVB-T/T2",
.frequency_stepsize = 166667, /* DVB-T only */ .frequency_stepsize_hz = 166667, /* DVB-T only */
.frequency_min = 47000000, /* DVB-T: 47125000 */ .frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */ .frequency_max_hz = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 870000, .symbol_rate_min = 870000,
.symbol_rate_max = 11700000, .symbol_rate_max = 11700000,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
@ -2562,9 +2566,9 @@ static struct dvb_frontend_ops common_ops_2837 = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2 }, .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2 },
.info = { .info = {
.name = "CXD2837 DVB-C DVB-T/T2", .name = "CXD2837 DVB-C DVB-T/T2",
.frequency_stepsize = 166667, /* DVB-T only */ .frequency_stepsize_hz = 166667, /* DVB-T only */
.frequency_min = 47000000, /* DVB-T: 47125000 */ .frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */ .frequency_max_hz = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 870000, .symbol_rate_min = 870000,
.symbol_rate_max = 11700000, .symbol_rate_max = 11700000,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
@ -2601,9 +2605,9 @@ static struct dvb_frontend_ops common_ops_2838 = {
.delsys = { SYS_ISDBT }, .delsys = { SYS_ISDBT },
.info = { .info = {
.name = "CXD2838 ISDB-T", .name = "CXD2838 ISDB-T",
.frequency_stepsize = 166667, .frequency_stepsize_hz = 166667,
.frequency_min = 47000000, .frequency_min_hz = 47000000,
.frequency_max = 865000000, .frequency_max_hz = 865000000,
.symbol_rate_min = 870000, .symbol_rate_min = 870000,
.symbol_rate_max = 11700000, .symbol_rate_max = 11700000,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |

View File

@ -31,7 +31,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "drxk.h" #include "drxk.h"
#include "drxk_hard.h" #include "drxk_hard.h"
@ -2804,10 +2804,12 @@ static int DVBTScCommand(struct drxk_state *state,
case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM: case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
status = Write16_0(state, OFDM_SC_RA_RAM_PARAM1__A, param1); status = Write16_0(state, OFDM_SC_RA_RAM_PARAM1__A, param1);
/* All commands using 1 parameters */ /* All commands using 1 parameters */
/* fall through */
case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING: case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
case OFDM_SC_RA_RAM_CMD_USER_IO: case OFDM_SC_RA_RAM_CMD_USER_IO:
status = Write16_0(state, OFDM_SC_RA_RAM_PARAM0__A, param0); status = Write16_0(state, OFDM_SC_RA_RAM_PARAM0__A, param0);
/* All commands using 0 parameters */ /* All commands using 0 parameters */
/* fall through */
case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM: case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
case OFDM_SC_RA_RAM_CMD_NULL: case OFDM_SC_RA_RAM_CMD_NULL:
/* Write command */ /* Write command */
@ -3215,7 +3217,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
case TRANSMISSION_MODE_AUTO: case TRANSMISSION_MODE_AUTO:
default: default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M; operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M;
/* fall through , try first guess DRX_FFTMODE_8K */ /* try first guess DRX_FFTMODE_8K */
/* fall through */
case TRANSMISSION_MODE_8K: case TRANSMISSION_MODE_8K:
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K; transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
break; break;
@ -3233,7 +3236,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
default: default:
case GUARD_INTERVAL_AUTO: case GUARD_INTERVAL_AUTO:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M; operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M;
/* fall through , try first guess DRX_GUARD_1DIV4 */ /* try first guess DRX_GUARD_1DIV4 */
/* fall through */
case GUARD_INTERVAL_1_4: case GUARD_INTERVAL_1_4:
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4; transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
break; break;
@ -3258,9 +3262,10 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
case HIERARCHY_NONE: case HIERARCHY_NONE:
default: default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M; operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M;
/* fall through , try first guess SC_RA_RAM_OP_PARAM_HIER_NO */ /* try first guess SC_RA_RAM_OP_PARAM_HIER_NO */
// transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; // transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO;
//break; //break;
/* fall through */
case HIERARCHY_1: case HIERARCHY_1:
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1; transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
break; break;
@ -3282,7 +3287,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
case QAM_AUTO: case QAM_AUTO:
default: default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M; operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M;
/* fall through , try first guess DRX_CONSTELLATION_QAM64 */ /* try first guess DRX_CONSTELLATION_QAM64 */
/* fall through */
case QAM_64: case QAM_64:
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64; transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
break; break;
@ -3325,7 +3331,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
case FEC_AUTO: case FEC_AUTO:
default: default:
operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M; operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M;
/* fall through , try first guess DRX_CODERATE_2DIV3 */ /* try first guess DRX_CODERATE_2DIV3 */
/* fall through */
case FEC_2_3 : case FEC_2_3 :
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3; transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
break; break;
@ -4994,12 +5001,12 @@ static int drxk_t_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_prop
} }
static struct dvb_frontend_ops drxk_c_ops = { static struct dvb_frontend_ops drxk_c_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBC_ANNEX_C },
.info = { .info = {
.name = "DRXK DVB-C", .name = "DRXK DVB-C",
.type = FE_QAM, .frequency_stepsize_hz = 62500,
.frequency_stepsize = 62500, .frequency_min_hz = 47000000,
.frequency_min = 47000000, .frequency_max_hz = 862000000,
.frequency_max = 862000000,
.symbol_rate_min = 870000, .symbol_rate_min = 870000,
.symbol_rate_max = 11700000, .symbol_rate_max = 11700000,
.caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 |
@ -5022,13 +5029,13 @@ static struct dvb_frontend_ops drxk_c_ops = {
}; };
static struct dvb_frontend_ops drxk_t_ops = { static struct dvb_frontend_ops drxk_t_ops = {
.delsys = { SYS_DVBT },
.info = { .info = {
.name = "DRXK DVB-T", .name = "DRXK DVB-T",
.type = FE_OFDM, .frequency_min_hz = 47125000,
.frequency_min = 47125000, .frequency_max_hz = 865000000,
.frequency_max = 865000000, .frequency_stepsize_hz = 166667,
.frequency_stepsize = 166667, .frequency_tolerance_hz = 0,
.frequency_tolerance = 0,
.caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
FE_CAN_FEC_AUTO | FE_CAN_FEC_AUTO |

View File

@ -30,7 +30,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "lnbh25.h" #include "lnbh25.h"
struct lnbh25 { struct lnbh25 {

View File

@ -32,7 +32,7 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/slab.h> #include <linux/slab.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "lnbp21.h" #include "lnbp21.h"
#include "lnbh24.h" #include "lnbh24.h"

View File

@ -41,7 +41,7 @@
#include <asm/div64.h> #include <asm/div64.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "mxl5xx.h" #include "mxl5xx.h"
#include "mxl5xx_regs.h" #include "mxl5xx_regs.h"
#include "mxl5xx_defs.h" #include "mxl5xx_defs.h"
@ -392,7 +392,7 @@ static void release(struct dvb_frontend *fe)
kfree(state); kfree(state);
} }
static int get_algo(struct dvb_frontend *fe) static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{ {
return DVBFE_ALGO_HW; return DVBFE_ALGO_HW;
} }
@ -786,6 +786,7 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
default: default:
break; break;
} }
/* fallthrough */
case SYS_DVBS: case SYS_DVBS:
switch ((MXL_HYDRA_MODULATION_E) switch ((MXL_HYDRA_MODULATION_E)
regData[DMD_MODULATION_SCHEME_ADDR]) { regData[DMD_MODULATION_SCHEME_ADDR]) {
@ -833,10 +834,10 @@ static struct dvb_frontend_ops mxl_ops = {
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */ .xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
.info = { .info = {
.name = "MXL5XX", .name = "MXL5XX",
.frequency_min = 300000, .frequency_min_hz = 300000000,
.frequency_max = 2350000, .frequency_max_hz = 2350000000,
.frequency_stepsize = 0, .frequency_stepsize_hz = 0,
.frequency_tolerance = 0, .frequency_tolerance_hz = 0,
.symbol_rate_min = 1000000, .symbol_rate_min = 1000000,
.symbol_rate_max = 45000000, .symbol_rate_max = 45000000,
.caps = FE_CAN_INVERSION_AUTO | .caps = FE_CAN_INVERSION_AUTO |

View File

@ -31,7 +31,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "stv0367dd.h" #include "stv0367dd.h"
#include "stv0367dd_regs.h" #include "stv0367dd_regs.h"
@ -2074,9 +2074,9 @@ static struct dvb_frontend_ops common_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT }, .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT },
.info = { .info = {
.name = "STV0367 DVB-C DVB-T", .name = "STV0367 DVB-C DVB-T",
.frequency_stepsize = 166667, /* DVB-T only */ .frequency_stepsize_hz = 166667, /* DVB-T only */
.frequency_min = 47000000, /* DVB-T: 47125000 */ .frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */ .frequency_max_hz = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 870000, .symbol_rate_min = 870000,
.symbol_rate_max = 11700000, .symbol_rate_max = 11700000,
.caps = /* DVB-C */ .caps = /* DVB-C */

View File

@ -28,7 +28,7 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/dvb/frontend.h> #include <linux/dvb/frontend.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "stv6110x.h" /* for demodulator internal modes */ #include "stv6110x.h" /* for demodulator internal modes */
@ -5142,10 +5142,10 @@ static struct dvb_frontend_ops stv090x_ops = {
#ifdef USE_API3 #ifdef USE_API3
.type = FE_QPSK, .type = FE_QPSK,
#endif #endif
.frequency_min = 950000, .frequency_min_hz = 950000000,
.frequency_max = 2150000, .frequency_max_hz = 2150000000,
.frequency_stepsize = 0, .frequency_stepsize_hz = 0,
.frequency_tolerance = 0, .frequency_tolerance_hz = 0,
.symbol_rate_min = 1000000, .symbol_rate_min = 1000000,
.symbol_rate_max = 45000000, .symbol_rate_max = 45000000,
.caps = FE_CAN_INVERSION_AUTO | .caps = FE_CAN_INVERSION_AUTO |

View File

@ -22,7 +22,7 @@
#ifndef __STV090x_PRIV_H #ifndef __STV090x_PRIV_H
#define __STV090x_PRIV_H #define __STV090x_PRIV_H
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#define FE_ERROR 0 #define FE_ERROR 0
#define FE_NOTICE 1 #define FE_NOTICE 1

View File

@ -31,7 +31,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "stv0910.h" #include "stv0910.h"
#include "stv0910_regs.h" #include "stv0910_regs.h"
@ -1581,7 +1581,7 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
return 0; return 0;
} }
static int get_algo(struct dvb_frontend *fe) static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{ {
return DVBFE_ALGO_HW; return DVBFE_ALGO_HW;
} }
@ -1801,10 +1801,10 @@ static struct dvb_frontend_ops stv0910_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
.info = { .info = {
.name = "STV0910", .name = "STV0910",
.frequency_min = 950000, .frequency_min_hz = 950000000,
.frequency_max = 2150000, .frequency_max_hz = 2150000000,
.frequency_stepsize = 0, .frequency_stepsize_hz = 0,
.frequency_tolerance = 0, .frequency_tolerance_hz = 0,
.symbol_rate_min = 100000, .symbol_rate_min = 100000,
.symbol_rate_max = 70000000, .symbol_rate_max = 70000000,
.caps = FE_CAN_INVERSION_AUTO | .caps = FE_CAN_INVERSION_AUTO |

View File

@ -26,7 +26,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "stv6110x_reg.h" #include "stv6110x_reg.h"
#include "stv6110x.h" #include "stv6110x.h"
@ -345,10 +345,10 @@ static void stv6110x_release(struct dvb_frontend *fe)
static const struct dvb_tuner_ops stv6110x_ops = { static const struct dvb_tuner_ops stv6110x_ops = {
.info = { .info = {
.name = "STV6110(A) Silicon Tuner", .name = "STV6110(A) Silicon Tuner",
.frequency_min = 950000, .frequency_min_hz = 950000000,
.frequency_max = 2150000, .frequency_max_hz = 2150000000,
.frequency_step = 0, .frequency_step_hz = 0,
}, },
.release = stv6110x_release .release = stv6110x_release
}; };

View File

@ -31,7 +31,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
static inline u32 MulDiv32(u32 a, u32 b, u32 c) static inline u32 MulDiv32(u32 a, u32 b, u32 c)
{ {
@ -706,9 +706,9 @@ static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
static struct dvb_tuner_ops tuner_ops = { static struct dvb_tuner_ops tuner_ops = {
.info = { .info = {
.name = "STV6111", .name = "STV6111",
.frequency_min = 950000, .frequency_min_hz = 950000000,
.frequency_max = 2150000, .frequency_max_hz = 2150000000,
.frequency_step = 0 .frequency_step_hz = 0
}, },
.init = init, .init = init,
.sleep = sleep, .sleep = sleep,

View File

@ -32,7 +32,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#ifndef CHK_ERROR #ifndef CHK_ERROR
#define CHK_ERROR(s) if ((status = s) < 0) break #define CHK_ERROR(s) if ((status = s) < 0) break
@ -889,9 +889,9 @@ static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
static struct dvb_tuner_ops tuner_ops = { static struct dvb_tuner_ops tuner_ops = {
.info = { .info = {
.name = "NXP TDA18212", .name = "NXP TDA18212",
.frequency_min = 47125000, .frequency_min_hz = 47125000,
.frequency_max = 865000000, .frequency_max_hz = 865000000,
.frequency_step = 62500 .frequency_step_hz = 62500
}, },
.init = init, .init = init,
.sleep = sleep, .sleep = sleep,

View File

@ -32,7 +32,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <asm/div64.h> #include <asm/div64.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
struct SStandardParam { struct SStandardParam {
s32 m_IFFrequency; s32 m_IFFrequency;
@ -1183,6 +1183,7 @@ static int set_params(struct dvb_frontend *fe,
switch (delsys) { switch (delsys) {
case SYS_DVBT: case SYS_DVBT:
/* fallthrough */
case SYS_DVBT2: case SYS_DVBT2:
switch (bw) { switch (bw) {
case 6000000: case 6000000:
@ -1197,7 +1198,9 @@ static int set_params(struct dvb_frontend *fe,
default: default:
return -EINVAL; return -EINVAL;
} }
break;
case SYS_DVBC_ANNEX_A: case SYS_DVBC_ANNEX_A:
/* fallthrough */
case SYS_DVBC_ANNEX_C: case SYS_DVBC_ANNEX_C:
if (bw <= 6000000) if (bw <= 6000000)
Standard = HF_DVBC_6MHZ; Standard = HF_DVBC_6MHZ;
@ -1292,9 +1295,9 @@ static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
static struct dvb_tuner_ops tuner_ops = { static struct dvb_tuner_ops tuner_ops = {
.info = { .info = {
.name = "NXP TDA18271C2D", .name = "NXP TDA18271C2D",
.frequency_min = 47125000, .frequency_min_hz = 47125000,
.frequency_max = 865000000, .frequency_max_hz = 865000000,
.frequency_step = 62500 .frequency_step_hz = 62500
}, },
.init = init, .init = init,
.sleep = sleep, .sleep = sleep,

View File

@ -117,7 +117,7 @@ struct dmx_ts_feed {
* specified by @filter_value that will be used on the filter * specified by @filter_value that will be used on the filter
* match logic. * match logic.
* @filter_mode: Contains a 16 bytes (128 bits) filter mode. * @filter_mode: Contains a 16 bytes (128 bits) filter mode.
* @parent: Pointer to struct dmx_section_feed. * @parent: Back-pointer to struct dmx_section_feed.
* @priv: Pointer to private data of the API client. * @priv: Pointer to private data of the API client.
* *
* *
@ -130,8 +130,9 @@ struct dmx_section_filter {
u8 filter_value[DMX_MAX_FILTER_SIZE]; u8 filter_value[DMX_MAX_FILTER_SIZE];
u8 filter_mask[DMX_MAX_FILTER_SIZE]; u8 filter_mask[DMX_MAX_FILTER_SIZE];
u8 filter_mode[DMX_MAX_FILTER_SIZE]; u8 filter_mode[DMX_MAX_FILTER_SIZE];
struct dmx_section_feed *parent; /* Back-pointer */ struct dmx_section_feed *parent;
void *priv; /* Pointer to private data of the API client */
void *priv;
}; };
/** /**
@ -193,6 +194,10 @@ struct dmx_section_feed {
* @buffer2: Pointer to the tail of the filtered TS packets, or NULL. * @buffer2: Pointer to the tail of the filtered TS packets, or NULL.
* @buffer2_length: Length of the TS data in buffer2. * @buffer2_length: Length of the TS data in buffer2.
* @source: Indicates which TS feed is the source of the callback. * @source: Indicates which TS feed is the source of the callback.
* @buffer_flags: Address where buffer flags are stored. Those are
* used to report discontinuity users via DVB
* memory mapped API, as defined by
* &enum dmx_buffer_flags.
* *
* This function callback prototype, provided by the client of the demux API, * This function callback prototype, provided by the client of the demux API,
* is called from the demux code. The function is only called when filtering * is called from the demux code. The function is only called when filtering
@ -245,7 +250,8 @@ typedef int (*dmx_ts_cb)(const u8 *buffer1,
size_t buffer1_length, size_t buffer1_length,
const u8 *buffer2, const u8 *buffer2,
size_t buffer2_length, size_t buffer2_length,
struct dmx_ts_feed *source); struct dmx_ts_feed *source,
u32 *buffer_flags);
/** /**
* typedef dmx_section_cb - DVB demux TS filter callback function prototype * typedef dmx_section_cb - DVB demux TS filter callback function prototype
@ -261,6 +267,10 @@ typedef int (*dmx_ts_cb)(const u8 *buffer1,
* including headers and CRC. * including headers and CRC.
* @source: Indicates which section feed is the source of the * @source: Indicates which section feed is the source of the
* callback. * callback.
* @buffer_flags: Address where buffer flags are stored. Those are
* used to report discontinuity users via DVB
* memory mapped API, as defined by
* &enum dmx_buffer_flags.
* *
* This function callback prototype, provided by the client of the demux API, * This function callback prototype, provided by the client of the demux API,
* is called from the demux code. The function is only called when * is called from the demux code. The function is only called when
@ -286,7 +296,8 @@ typedef int (*dmx_section_cb)(const u8 *buffer1,
size_t buffer1_len, size_t buffer1_len,
const u8 *buffer2, const u8 *buffer2,
size_t buffer2_len, size_t buffer2_len,
struct dmx_section_filter *source); struct dmx_section_filter *source,
u32 *buffer_flags);
/* /*
* DVB Front-End * DVB Front-End

View File

@ -0,0 +1,220 @@
/*
* dmxdev.h
*
* Copyright (C) 2000 Ralph Metzler & Marcus Metzler
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _DMXDEV_H_
#define _DMXDEV_H_
#include <linux/types.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/wait.h>
#include <linux/fs.h>
#include <linux/string.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/dvb/dmx.h>
#include <media/dvbdev.h>
#include <media/demux.h>
#include <media/dvb_ringbuffer.h>
#ifdef CONFIG_DVB_MMAP
#include <media/dvb_vb2.h>
#endif
/**
* enum dmxdev_type - type of demux filter type.
*
* @DMXDEV_TYPE_NONE: no filter set.
* @DMXDEV_TYPE_SEC: section filter.
* @DMXDEV_TYPE_PES: Program Elementary Stream (PES) filter.
*/
enum dmxdev_type {
DMXDEV_TYPE_NONE,
DMXDEV_TYPE_SEC,
DMXDEV_TYPE_PES,
};
/**
* enum dmxdev_state - state machine for the dmxdev.
*
* @DMXDEV_STATE_FREE: indicates that the filter is freed.
* @DMXDEV_STATE_ALLOCATED: indicates that the filter was allocated
* to be used.
* @DMXDEV_STATE_SET: indicates that the filter parameters are set.
* @DMXDEV_STATE_GO: indicates that the filter is running.
* @DMXDEV_STATE_DONE: indicates that a packet was already filtered
* and the filter is now disabled.
* Set only if %DMX_ONESHOT. See
* &dmx_sct_filter_params.
* @DMXDEV_STATE_TIMEDOUT: Indicates a timeout condition.
*/
enum dmxdev_state {
DMXDEV_STATE_FREE,
DMXDEV_STATE_ALLOCATED,
DMXDEV_STATE_SET,
DMXDEV_STATE_GO,
DMXDEV_STATE_DONE,
DMXDEV_STATE_TIMEDOUT
};
/**
* struct dmxdev_feed - digital TV dmxdev feed
*
* @pid: Program ID to be filtered
* @ts: pointer to &struct dmx_ts_feed
* @next: &struct list_head pointing to the next feed.
*/
struct dmxdev_feed {
u16 pid;
struct dmx_ts_feed *ts;
struct list_head next;
};
/**
* struct dmxdev_filter - digital TV dmxdev filter
*
* @filter: a union describing a dmxdev filter.
* Currently used only for section filters.
* @filter.sec: a &struct dmx_section_filter pointer.
* For section filter only.
* @feed: a union describing a dmxdev feed.
* Depending on the filter type, it can be either
* @feed.ts or @feed.sec.
* @feed.ts: a &struct list_head list.
* For TS and PES feeds.
* @feed.sec: a &struct dmx_section_feed pointer.
* For section feed only.
* @params: a union describing dmxdev filter parameters.
* Depending on the filter type, it can be either
* @params.sec or @params.pes.
* @params.sec: a &struct dmx_sct_filter_params embedded struct.
* For section filter only.
* @params.pes: a &struct dmx_pes_filter_params embedded struct.
* For PES filter only.
* @type: type of the dmxdev filter, as defined by &enum dmxdev_type.
* @state: state of the dmxdev filter, as defined by &enum dmxdev_state.
* @dev: pointer to &struct dmxdev.
* @buffer: an embedded &struct dvb_ringbuffer buffer.
* @vb2_ctx: control struct for VB2 handler
* @mutex: protects the access to &struct dmxdev_filter.
* @timer: &struct timer_list embedded timer, used to check for
* feed timeouts.
* Only for section filter.
* @todo: index for the @secheader.
* Only for section filter.
* @secheader: buffer cache to parse the section header.
* Only for section filter.
*/
struct dmxdev_filter {
union {
struct dmx_section_filter *sec;
} filter;
union {
/* list of TS and PES feeds (struct dmxdev_feed) */
struct list_head ts;
struct dmx_section_feed *sec;
} feed;
union {
struct dmx_sct_filter_params sec;
struct dmx_pes_filter_params pes;
} params;
enum dmxdev_type type;
enum dmxdev_state state;
struct dmxdev *dev;
struct dvb_ringbuffer buffer;
#ifdef CONFIG_DVB_MMAP
struct dvb_vb2_ctx vb2_ctx;
#endif
struct mutex mutex;
/* only for sections */
struct timer_list timer;
int todo;
u8 secheader[3];
};
/**
* struct dmxdev - Describes a digital TV demux device.
*
* @dvbdev: pointer to &struct dvb_device associated with
* the demux device node.
* @dvr_dvbdev: pointer to &struct dvb_device associated with
* the dvr device node.
* @filter: pointer to &struct dmxdev_filter.
* @demux: pointer to &struct dmx_demux.
* @filternum: number of filters.
* @capabilities: demux capabilities as defined by &enum dmx_demux_caps.
* @may_do_mmap: flag used to indicate if the device may do mmap.
* @exit: flag to indicate that the demux is being released.
* @dvr_orig_fe: pointer to &struct dmx_frontend.
* @dvr_buffer: embedded &struct dvb_ringbuffer for DVB output.
* @dvr_vb2_ctx: control struct for VB2 handler
* @mutex: protects the usage of this structure.
* @lock: protects access to &dmxdev->filter->data.
*/
struct dmxdev {
struct dvb_device *dvbdev;
struct dvb_device *dvr_dvbdev;
struct dmxdev_filter *filter;
struct dmx_demux *demux;
int filternum;
int capabilities;
unsigned int may_do_mmap:1;
unsigned int exit:1;
#define DMXDEV_CAP_DUPLEX 1
struct dmx_frontend *dvr_orig_fe;
struct dvb_ringbuffer dvr_buffer;
#define DVR_BUFFER_SIZE (10*188*1024)
#ifdef CONFIG_DVB_MMAP
struct dvb_vb2_ctx dvr_vb2_ctx;
#endif
struct mutex mutex;
spinlock_t lock;
};
/**
* dvb_dmxdev_init - initializes a digital TV demux and registers both demux
* and DVR devices.
*
* @dmxdev: pointer to &struct dmxdev.
* @adap: pointer to &struct dvb_adapter.
*/
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *adap);
/**
* dvb_dmxdev_release - releases a digital TV demux and unregisters it.
*
* @dmxdev: pointer to &struct dmxdev.
*/
void dvb_dmxdev_release(struct dmxdev *dmxdev);
#endif /* _DMXDEV_H_ */

View File

@ -20,7 +20,7 @@
#include <linux/list.h> #include <linux/list.h>
#include <linux/dvb/ca.h> #include <linux/dvb/ca.h>
#include "dvbdev.h" #include <media/dvbdev.h>
#define DVB_CA_EN50221_POLL_CAM_PRESENT 1 #define DVB_CA_EN50221_POLL_CAM_PRESENT 1
#define DVB_CA_EN50221_POLL_CAM_CHANGED 2 #define DVB_CA_EN50221_POLL_CAM_CHANGED 2

View File

@ -0,0 +1,354 @@
/*
* dvb_demux.h: DVB kernel demux API
*
* Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler
* for convergence integrated media GmbH
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public License
* as published by the Free Software Foundation; either version 2.1
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#ifndef _DVB_DEMUX_H_
#define _DVB_DEMUX_H_
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/spinlock.h>
#include <linux/mutex.h>
#include <media/demux.h>
/**
* enum dvb_dmx_filter_type - type of demux feed.
*
* @DMX_TYPE_TS: feed is in TS mode.
* @DMX_TYPE_SEC: feed is in Section mode.
*/
enum dvb_dmx_filter_type {
DMX_TYPE_TS,
DMX_TYPE_SEC,
};
/**
* enum dvb_dmx_state - state machine for a demux filter.
*
* @DMX_STATE_FREE: indicates that the filter is freed.
* @DMX_STATE_ALLOCATED: indicates that the filter was allocated
* to be used.
* @DMX_STATE_READY: indicates that the filter is ready
* to be used.
* @DMX_STATE_GO: indicates that the filter is running.
*/
enum dvb_dmx_state {
DMX_STATE_FREE,
DMX_STATE_ALLOCATED,
DMX_STATE_READY,
DMX_STATE_GO,
};
#define DVB_DEMUX_MASK_MAX 18
#define MAX_PID 0x1fff
#define SPEED_PKTS_INTERVAL 50000
/**
* struct dvb_demux_filter - Describes a DVB demux section filter.
*
* @filter: Section filter as defined by &struct dmx_section_filter.
* @maskandmode: logical ``and`` bit mask.
* @maskandnotmode: logical ``and not`` bit mask.
* @doneq: flag that indicates when a filter is ready.
* @next: pointer to the next section filter.
* @feed: &struct dvb_demux_feed pointer.
* @index: index of the used demux filter.
* @state: state of the filter as described by &enum dvb_dmx_state.
* @type: type of the filter as described
* by &enum dvb_dmx_filter_type.
*/
struct dvb_demux_filter {
struct dmx_section_filter filter;
u8 maskandmode[DMX_MAX_FILTER_SIZE];
u8 maskandnotmode[DMX_MAX_FILTER_SIZE];
bool doneq;
struct dvb_demux_filter *next;
struct dvb_demux_feed *feed;
int index;
enum dvb_dmx_state state;
enum dvb_dmx_filter_type type;
/* private: used only by av7110 */
u16 hw_handle;
};
/**
* struct dvb_demux_feed - describes a DVB field
*
* @feed: a union describing a digital TV feed.
* Depending on the feed type, it can be either
* @feed.ts or @feed.sec.
* @feed.ts: a &struct dmx_ts_feed pointer.
* For TS feed only.
* @feed.sec: a &struct dmx_section_feed pointer.
* For section feed only.
* @cb: a union describing digital TV callbacks.
* Depending on the feed type, it can be either
* @cb.ts or @cb.sec.
* @cb.ts: a dmx_ts_cb() calback function pointer.
* For TS feed only.
* @cb.sec: a dmx_section_cb() callback function pointer.
* For section feed only.
* @demux: pointer to &struct dvb_demux.
* @priv: private data that can optionally be used by a DVB driver.
* @type: type of the filter, as defined by &enum dvb_dmx_filter_type.
* @state: state of the filter as defined by &enum dvb_dmx_state.
* @pid: PID to be filtered.
* @timeout: feed timeout.
* @filter: pointer to &struct dvb_demux_filter.
* @buffer_flags: Buffer flags used to report discontinuity users via DVB
* memory mapped API, as defined by &enum dmx_buffer_flags.
* @ts_type: type of TS, as defined by &enum ts_filter_type.
* @pes_type: type of PES, as defined by &enum dmx_ts_pes.
* @cc: MPEG-TS packet continuity counter
* @pusi_seen: if true, indicates that a discontinuity was detected.
* it is used to prevent feeding of garbage from previous section.
* @peslen: length of the PES (Packet Elementary Stream).
* @list_head: head for the list of digital TV demux feeds.
* @index: a unique index for each feed. Can be used as hardware
* pid filter index.
*/
struct dvb_demux_feed {
union {
struct dmx_ts_feed ts;
struct dmx_section_feed sec;
} feed;
union {
dmx_ts_cb ts;
dmx_section_cb sec;
} cb;
struct dvb_demux *demux;
void *priv;
enum dvb_dmx_filter_type type;
enum dvb_dmx_state state;
u16 pid;
ktime_t timeout;
struct dvb_demux_filter *filter;
u32 buffer_flags;
enum ts_filter_type ts_type;
enum dmx_ts_pes pes_type;
int cc;
bool pusi_seen;
u16 peslen;
struct list_head list_head;
unsigned int index;
};
/**
* struct dvb_demux - represents a digital TV demux
* @dmx: embedded &struct dmx_demux with demux capabilities
* and callbacks.
* @priv: private data that can optionally be used by
* a DVB driver.
* @filternum: maximum amount of DVB filters.
* @feednum: maximum amount of DVB feeds.
* @start_feed: callback routine to be called in order to start
* a DVB feed.
* @stop_feed: callback routine to be called in order to stop
* a DVB feed.
* @write_to_decoder: callback routine to be called if the feed is TS and
* it is routed to an A/V decoder, when a new TS packet
* is received.
* Used only on av7110-av.c.
* @check_crc32: callback routine to check CRC. If not initialized,
* dvb_demux will use an internal one.
* @memcopy: callback routine to memcopy received data.
* If not initialized, dvb_demux will default to memcpy().
* @users: counter for the number of demux opened file descriptors.
* Currently, it is limited to 10 users.
* @filter: pointer to &struct dvb_demux_filter.
* @feed: pointer to &struct dvb_demux_feed.
* @frontend_list: &struct list_head with frontends used by the demux.
* @pesfilter: array of &struct dvb_demux_feed with the PES types
* that will be filtered.
* @pids: list of filtered program IDs.
* @feed_list: &struct list_head with feeds.
* @tsbuf: temporary buffer used internally to store TS packets.
* @tsbufp: temporary buffer index used internally.
* @mutex: pointer to &struct mutex used to protect feed set
* logic.
* @lock: pointer to &spinlock_t, used to protect buffer handling.
* @cnt_storage: buffer used for TS/TEI continuity check.
* @speed_last_time: &ktime_t used for TS speed check.
* @speed_pkts_cnt: packets count used for TS speed check.
*/
struct dvb_demux {
struct dmx_demux dmx;
void *priv;
int filternum;
int feednum;
int (*start_feed)(struct dvb_demux_feed *feed);
int (*stop_feed)(struct dvb_demux_feed *feed);
int (*write_to_decoder)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
u32 (*check_crc32)(struct dvb_demux_feed *feed,
const u8 *buf, size_t len);
void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst,
const u8 *src, size_t len);
int users;
#define MAX_DVB_DEMUX_USERS 10
struct dvb_demux_filter *filter;
struct dvb_demux_feed *feed;
struct list_head frontend_list;
struct dvb_demux_feed *pesfilter[DMX_PES_OTHER];
u16 pids[DMX_PES_OTHER];
#define DMX_MAX_PID 0x2000
struct list_head feed_list;
u8 tsbuf[204];
int tsbufp;
struct mutex mutex;
spinlock_t lock;
uint8_t *cnt_storage; /* for TS continuity check */
ktime_t speed_last_time; /* for TS speed check */
uint32_t speed_pkts_cnt; /* for TS speed check */
/* private: used only on av7110 */
int playing;
int recording;
};
/**
* dvb_dmx_init - initialize a digital TV demux struct.
*
* @demux: &struct dvb_demux to be initialized.
*
* Before being able to register a digital TV demux struct, drivers
* should call this routine. On its typical usage, some fields should
* be initialized at the driver before calling it.
*
* A typical usecase is::
*
* dvb->demux.dmx.capabilities =
* DMX_TS_FILTERING | DMX_SECTION_FILTERING |
* DMX_MEMORY_BASED_FILTERING;
* dvb->demux.priv = dvb;
* dvb->demux.filternum = 256;
* dvb->demux.feednum = 256;
* dvb->demux.start_feed = driver_start_feed;
* dvb->demux.stop_feed = driver_stop_feed;
* ret = dvb_dmx_init(&dvb->demux);
* if (ret < 0)
* return ret;
*/
int dvb_dmx_init(struct dvb_demux *demux);
/**
* dvb_dmx_release - releases a digital TV demux internal buffers.
*
* @demux: &struct dvb_demux to be released.
*
* The DVB core internally allocates data at @demux. This routine
* releases those data. Please notice that the struct itelf is not
* released, as it can be embedded on other structs.
*/
void dvb_dmx_release(struct dvb_demux *demux);
/**
* dvb_dmx_swfilter_packets - use dvb software filter for a buffer with
* multiple MPEG-TS packets with 188 bytes each.
*
* @demux: pointer to &struct dvb_demux
* @buf: buffer with data to be filtered
* @count: number of MPEG-TS packets with size of 188.
*
* The routine will discard a DVB packet that don't start with 0x47.
*
* Use this routine if the DVB demux fills MPEG-TS buffers that are
* already aligned.
*
* NOTE: The @buf size should have size equal to ``count * 188``.
*/
void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
size_t count);
/**
* dvb_dmx_swfilter - use dvb software filter for a buffer with
* multiple MPEG-TS packets with 188 bytes each.
*
* @demux: pointer to &struct dvb_demux
* @buf: buffer with data to be filtered
* @count: number of MPEG-TS packets with size of 188.
*
* If a DVB packet doesn't start with 0x47, it will seek for the first
* byte that starts with 0x47.
*
* Use this routine if the DVB demux fill buffers that may not start with
* a packet start mark (0x47).
*
* NOTE: The @buf size should have size equal to ``count * 188``.
*/
void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count);
/**
* dvb_dmx_swfilter_204 - use dvb software filter for a buffer with
* multiple MPEG-TS packets with 204 bytes each.
*
* @demux: pointer to &struct dvb_demux
* @buf: buffer with data to be filtered
* @count: number of MPEG-TS packets with size of 204.
*
* If a DVB packet doesn't start with 0x47, it will seek for the first
* byte that starts with 0x47.
*
* Use this routine if the DVB demux fill buffers that may not start with
* a packet start mark (0x47).
*
* NOTE: The @buf size should have size equal to ``count * 204``.
*/
void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf,
size_t count);
/**
* dvb_dmx_swfilter_raw - make the raw data available to userspace without
* filtering
*
* @demux: pointer to &struct dvb_demux
* @buf: buffer with data
* @count: number of packets to be passed. The actual size of each packet
* depends on the &dvb_demux->feed->cb.ts logic.
*
* Use it if the driver needs to deliver the raw payload to userspace without
* passing through the kernel demux. That is meant to support some
* delivery systems that aren't based on MPEG-TS.
*
* This function relies on &dvb_demux->feed->cb.ts to actually handle the
* buffer.
*/
void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf,
size_t count);
#endif /* _DVB_DEMUX_H_ */

View File

@ -46,10 +46,11 @@
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/mutex.h> #include <linux/mutex.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/dvb/frontend.h> #include <linux/dvb/frontend.h>
#include "dvbdev.h" #include <media/dvbdev.h>
/* /*
* Maximum number of Delivery systems per frontend. It * Maximum number of Delivery systems per frontend. It
@ -57,6 +58,10 @@
*/ */
#define MAX_DELSYS 16 #define MAX_DELSYS 16
/* Helper definitions to be used at frontend drivers */
#define kHz 1000UL
#define MHz 1000000UL
/** /**
* struct dvb_frontend_tune_settings - parameters to adjust frontend tuning * struct dvb_frontend_tune_settings - parameters to adjust frontend tuning
* *
@ -78,22 +83,19 @@ struct dvb_frontend;
* struct dvb_tuner_info - Frontend name and min/max ranges/bandwidths * struct dvb_tuner_info - Frontend name and min/max ranges/bandwidths
* *
* @name: name of the Frontend * @name: name of the Frontend
* @frequency_min: minimal frequency supported * @frequency_min_hz: minimal frequency supported in Hz
* @frequency_max: maximum frequency supported * @frequency_max_hz: maximum frequency supported in Hz
* @frequency_step: frequency step * @frequency_step_hz: frequency step in Hz
* @bandwidth_min: minimal frontend bandwidth supported * @bandwidth_min: minimal frontend bandwidth supported
* @bandwidth_max: maximum frontend bandwidth supported * @bandwidth_max: maximum frontend bandwidth supported
* @bandwidth_step: frontend bandwidth step * @bandwidth_step: frontend bandwidth step
*
* NOTE: frequency parameters are in Hz, for terrestrial/cable or kHz for
* satellite.
*/ */
struct dvb_tuner_info { struct dvb_tuner_info {
char name[128]; char name[128];
u32 frequency_min; u32 frequency_min_hz;
u32 frequency_max; u32 frequency_max_hz;
u32 frequency_step; u32 frequency_step_hz;
u32 bandwidth_min; u32 bandwidth_min;
u32 bandwidth_max; u32 bandwidth_max;
@ -104,10 +106,10 @@ struct dvb_tuner_info {
* struct analog_parameters - Parameters to tune into an analog/radio channel * struct analog_parameters - Parameters to tune into an analog/radio channel
* *
* @frequency: Frequency used by analog TV tuner (either in 62.5 kHz step, * @frequency: Frequency used by analog TV tuner (either in 62.5 kHz step,
* for TV, or 62.5 Hz for radio) * for TV, or 62.5 Hz for radio)
* @mode: Tuner mode, as defined on enum v4l2_tuner_type * @mode: Tuner mode, as defined on enum v4l2_tuner_type
* @audmode: Audio mode as defined for the rxsubchans field at videodev2.h, * @audmode: Audio mode as defined for the rxsubchans field at videodev2.h,
* e. g. V4L2_TUNER_MODE_* * e. g. V4L2_TUNER_MODE_*
* @std: TV standard bitmap as defined at videodev2.h, e. g. V4L2_STD_* * @std: TV standard bitmap as defined at videodev2.h, e. g. V4L2_STD_*
* *
* Hybrid tuners should be supported by both V4L2 and DVB APIs. This * Hybrid tuners should be supported by both V4L2 and DVB APIs. This
@ -145,10 +147,10 @@ struct analog_parameters {
* These devices have AUTO recovery capabilities from LOCK failure * These devices have AUTO recovery capabilities from LOCK failure
*/ */
enum dvbfe_algo { enum dvbfe_algo {
DVBFE_ALGO_HW = (1 << 0), DVBFE_ALGO_HW = BIT(0),
DVBFE_ALGO_SW = (1 << 1), DVBFE_ALGO_SW = BIT(1),
DVBFE_ALGO_CUSTOM = (1 << 2), DVBFE_ALGO_CUSTOM = BIT(2),
DVBFE_ALGO_RECOVERY = (1 << 31) DVBFE_ALGO_RECOVERY = BIT(31),
}; };
/** /**
@ -164,7 +166,7 @@ enum dvbfe_algo {
* The frontend search for a signal failed * The frontend search for a signal failed
* *
* @DVBFE_ALGO_SEARCH_INVALID: * @DVBFE_ALGO_SEARCH_INVALID:
* The frontend search algorith was probably supplied with invalid * The frontend search algorithm was probably supplied with invalid
* parameters and the search is an invalid one * parameters and the search is an invalid one
* *
* @DVBFE_ALGO_SEARCH_ERROR: * @DVBFE_ALGO_SEARCH_ERROR:
@ -174,19 +176,19 @@ enum dvbfe_algo {
* The frontend search algorithm was requested to search again * The frontend search algorithm was requested to search again
*/ */
enum dvbfe_search { enum dvbfe_search {
DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0), DVBFE_ALGO_SEARCH_SUCCESS = BIT(0),
DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1), DVBFE_ALGO_SEARCH_ASLEEP = BIT(1),
DVBFE_ALGO_SEARCH_FAILED = (1 << 2), DVBFE_ALGO_SEARCH_FAILED = BIT(2),
DVBFE_ALGO_SEARCH_INVALID = (1 << 3), DVBFE_ALGO_SEARCH_INVALID = BIT(3),
DVBFE_ALGO_SEARCH_AGAIN = (1 << 4), DVBFE_ALGO_SEARCH_AGAIN = BIT(4),
DVBFE_ALGO_SEARCH_ERROR = (1 << 31), DVBFE_ALGO_SEARCH_ERROR = BIT(31),
}; };
/** /**
* struct dvb_tuner_ops - Tuner information and callbacks * struct dvb_tuner_ops - Tuner information and callbacks
* *
* @info: embedded struct dvb_tuner_info with tuner properties * @info: embedded &struct dvb_tuner_info with tuner properties
* @release: callback function called when frontend is dettached. * @release: callback function called when frontend is detached.
* drivers should free any allocated memory. * drivers should free any allocated memory.
* @init: callback function used to initialize the tuner device. * @init: callback function used to initialize the tuner device.
* @sleep: callback function used to put the tuner to sleep. * @sleep: callback function used to put the tuner to sleep.
@ -196,25 +198,25 @@ enum dvbfe_search {
* resuming from suspend. * resuming from suspend.
* @set_params: callback function used to inform the tuner to tune * @set_params: callback function used to inform the tuner to tune
* into a digital TV channel. The properties to be used * into a digital TV channel. The properties to be used
* are stored at @dvb_frontend.dtv_property_cache;. The * are stored at &struct dvb_frontend.dtv_property_cache.
* tuner demod can change the parameters to reflect the * The tuner demod can change the parameters to reflect
* changes needed for the channel to be tuned, and * the changes needed for the channel to be tuned, and
* update statistics. This is the recommended way to set * update statistics. This is the recommended way to set
* the tuner parameters and should be used on newer * the tuner parameters and should be used on newer
* drivers. * drivers.
* @set_analog_params: callback function used to tune into an analog TV * @set_analog_params: callback function used to tune into an analog TV
* channel on hybrid tuners. It passes @analog_parameters; * channel on hybrid tuners. It passes @analog_parameters
* to the driver. * to the driver.
* @set_config: callback function used to send some tuner-specific * @set_config: callback function used to send some tuner-specific
* parameters. * parameters.
* @get_frequency: get the actual tuned frequency * @get_frequency: get the actual tuned frequency
* @get_bandwidth: get the bandwitdh used by the low pass filters * @get_bandwidth: get the bandwidth used by the low pass filters
* @get_if_frequency: get the Intermediate Frequency, in Hz. For baseband, * @get_if_frequency: get the Intermediate Frequency, in Hz. For baseband,
* should return 0. * should return 0.
* @get_status: returns the frontend lock status * @get_status: returns the frontend lock status
* @get_rf_strength: returns the RF signal strengh. Used mostly to support * @get_rf_strength: returns the RF signal strength. Used mostly to support
* analog TV and radio. Digital TV should report, instead, * analog TV and radio. Digital TV should report, instead,
* via DVBv5 API (@dvb_frontend.dtv_property_cache;). * via DVBv5 API (&struct dvb_frontend.dtv_property_cache).
* @get_afc: Used only by analog TV core. Reports the frequency * @get_afc: Used only by analog TV core. Reports the frequency
* drift due to AFC. * drift due to AFC.
* @calc_regs: callback function used to pass register data settings * @calc_regs: callback function used to pass register data settings
@ -222,7 +224,7 @@ enum dvbfe_search {
* @set_frequency: Set a new frequency. Shouldn't be used on newer drivers. * @set_frequency: Set a new frequency. Shouldn't be used on newer drivers.
* @set_bandwidth: Set a new frequency. Shouldn't be used on newer drivers. * @set_bandwidth: Set a new frequency. Shouldn't be used on newer drivers.
* *
* NOTE: frequencies used on get_frequency and set_frequency are in Hz for * NOTE: frequencies used on @get_frequency and @set_frequency are in Hz for
* terrestrial/cable or kHz for satellite. * terrestrial/cable or kHz for satellite.
* *
*/ */
@ -236,7 +238,7 @@ struct dvb_tuner_ops {
int (*suspend)(struct dvb_frontend *fe); int (*suspend)(struct dvb_frontend *fe);
int (*resume)(struct dvb_frontend *fe); int (*resume)(struct dvb_frontend *fe);
/* This is the recomended way to set the tuner */ /* This is the recommended way to set the tuner */
int (*set_params)(struct dvb_frontend *fe); int (*set_params)(struct dvb_frontend *fe);
int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p);
@ -288,14 +290,14 @@ struct analog_demod_info {
* @set_params: callback function used to inform the demod to set the * @set_params: callback function used to inform the demod to set the
* demodulator parameters needed to decode an analog or * demodulator parameters needed to decode an analog or
* radio channel. The properties are passed via * radio channel. The properties are passed via
* struct @analog_params;. * &struct analog_params.
* @has_signal: returns 0xffff if has signal, or 0 if it doesn't. * @has_signal: returns 0xffff if has signal, or 0 if it doesn't.
* @get_afc: Used only by analog TV core. Reports the frequency * @get_afc: Used only by analog TV core. Reports the frequency
* drift due to AFC. * drift due to AFC.
* @tuner_status: callback function that returns tuner status bits, e. g. * @tuner_status: callback function that returns tuner status bits, e. g.
* TUNER_STATUS_LOCKED and TUNER_STATUS_STEREO. * %TUNER_STATUS_LOCKED and %TUNER_STATUS_STEREO.
* @standby: set the tuner to standby mode. * @standby: set the tuner to standby mode.
* @release: callback function called when frontend is dettached. * @release: callback function called when frontend is detached.
* drivers should free any allocated memory. * drivers should free any allocated memory.
* @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C * @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C
* mux support instead. * mux support instead.
@ -321,20 +323,48 @@ struct analog_demod_ops {
struct dtv_frontend_properties; struct dtv_frontend_properties;
/**
* struct dvb_frontend_internal_info - Frontend properties and capabilities
*
* @name: Name of the frontend
* @frequency_min_hz: Minimal frequency supported by the frontend.
* @frequency_max_hz: Minimal frequency supported by the frontend.
* @frequency_stepsize_hz: All frequencies are multiple of this value.
* @frequency_tolerance_hz: Frequency tolerance.
* @symbol_rate_min: Minimal symbol rate, in bauds
* (for Cable/Satellite systems).
* @symbol_rate_max: Maximal symbol rate, in bauds
* (for Cable/Satellite systems).
* @symbol_rate_tolerance: Maximal symbol rate tolerance, in ppm
* (for Cable/Satellite systems).
* @caps: Capabilities supported by the frontend,
* as specified in &enum fe_caps.
*/
struct dvb_frontend_internal_info {
char name[128];
u32 frequency_min_hz;
u32 frequency_max_hz;
u32 frequency_stepsize_hz;
u32 frequency_tolerance_hz;
u32 symbol_rate_min;
u32 symbol_rate_max;
u32 symbol_rate_tolerance;
enum fe_caps caps;
};
/** /**
* struct dvb_frontend_ops - Demodulation information and callbacks for * struct dvb_frontend_ops - Demodulation information and callbacks for
* ditialt TV * ditialt TV
* *
* @info: embedded struct dvb_tuner_info with tuner properties * @info: embedded &struct dvb_tuner_info with tuner properties
* @delsys: Delivery systems supported by the frontend * @delsys: Delivery systems supported by the frontend
* @detach: callback function called when frontend is detached. * @detach: callback function called when frontend is detached.
* drivers should clean up, but not yet free the struct * drivers should clean up, but not yet free the &struct
* dvb_frontend allocation. * dvb_frontend allocation.
* @release: callback function called when frontend is ready to be * @release: callback function called when frontend is ready to be
* freed. * freed.
* drivers should free any allocated memory. * drivers should free any allocated memory.
* @release_sec: callback function requesting that the Satelite Equipment * @release_sec: callback function requesting that the Satellite Equipment
* Control (SEC) driver to release and free any memory * Control (SEC) driver to release and free any memory
* allocated by the driver. * allocated by the driver.
* @init: callback function used to initialize the tuner device. * @init: callback function used to initialize the tuner device.
@ -343,57 +373,57 @@ struct dtv_frontend_properties;
* allow other drivers to write data into their registers. * allow other drivers to write data into their registers.
* Should not be used on new drivers. * Should not be used on new drivers.
* @tune: callback function used by demod drivers that use * @tune: callback function used by demod drivers that use
* @DVBFE_ALGO_HW; to tune into a frequency. * @DVBFE_ALGO_HW to tune into a frequency.
* @get_frontend_algo: returns the desired hardware algorithm. * @get_frontend_algo: returns the desired hardware algorithm.
* @set_frontend: callback function used to inform the demod to set the * @set_frontend: callback function used to inform the demod to set the
* parameters for demodulating a digital TV channel. * parameters for demodulating a digital TV channel.
* The properties to be used are stored at * The properties to be used are stored at &struct
* @dvb_frontend.dtv_property_cache;. The demod can change * dvb_frontend.dtv_property_cache. The demod can change
* the parameters to reflect the changes needed for the * the parameters to reflect the changes needed for the
* channel to be decoded, and update statistics. * channel to be decoded, and update statistics.
* @get_tune_settings: callback function * @get_tune_settings: callback function
* @get_frontend: callback function used to inform the parameters * @get_frontend: callback function used to inform the parameters
* actuall in use. The properties to be used are stored at * actuall in use. The properties to be used are stored at
* @dvb_frontend.dtv_property_cache; and update * &struct dvb_frontend.dtv_property_cache and update
* statistics. Please notice that it should not return * statistics. Please notice that it should not return
* an error code if the statistics are not available * an error code if the statistics are not available
* because the demog is not locked. * because the demog is not locked.
* @read_status: returns the locking status of the frontend. * @read_status: returns the locking status of the frontend.
* @read_ber: legacy callback function to return the bit error rate. * @read_ber: legacy callback function to return the bit error rate.
* Newer drivers should provide such info via DVBv5 API, * Newer drivers should provide such info via DVBv5 API,
* e. g. @set_frontend;/@get_frontend;, implementing this * e. g. @set_frontend;/@get_frontend, implementing this
* callback only if DVBv3 API compatibility is wanted. * callback only if DVBv3 API compatibility is wanted.
* @read_signal_strength: legacy callback function to return the signal * @read_signal_strength: legacy callback function to return the signal
* strength. Newer drivers should provide such info via * strength. Newer drivers should provide such info via
* DVBv5 API, e. g. @set_frontend;/@get_frontend;, * DVBv5 API, e. g. @set_frontend/@get_frontend,
* implementing this callback only if DVBv3 API * implementing this callback only if DVBv3 API
* compatibility is wanted. * compatibility is wanted.
* @read_snr: legacy callback function to return the Signal/Noise * @read_snr: legacy callback function to return the Signal/Noise
* rate. Newer drivers should provide such info via * rate. Newer drivers should provide such info via
* DVBv5 API, e. g. @set_frontend;/@get_frontend;, * DVBv5 API, e. g. @set_frontend/@get_frontend,
* implementing this callback only if DVBv3 API * implementing this callback only if DVBv3 API
* compatibility is wanted. * compatibility is wanted.
* @read_ucblocks: legacy callback function to return the Uncorrected Error * @read_ucblocks: legacy callback function to return the Uncorrected Error
* Blocks. Newer drivers should provide such info via * Blocks. Newer drivers should provide such info via
* DVBv5 API, e. g. @set_frontend;/@get_frontend;, * DVBv5 API, e. g. @set_frontend/@get_frontend,
* implementing this callback only if DVBv3 API * implementing this callback only if DVBv3 API
* compatibility is wanted. * compatibility is wanted.
* @diseqc_reset_overload: callback function to implement the * @diseqc_reset_overload: callback function to implement the
* FE_DISEQC_RESET_OVERLOAD ioctl (only Satellite) * FE_DISEQC_RESET_OVERLOAD() ioctl (only Satellite)
* @diseqc_send_master_cmd: callback function to implement the * @diseqc_send_master_cmd: callback function to implement the
* FE_DISEQC_SEND_MASTER_CMD ioctl (only Satellite). * FE_DISEQC_SEND_MASTER_CMD() ioctl (only Satellite).
* @diseqc_recv_slave_reply: callback function to implement the * @diseqc_recv_slave_reply: callback function to implement the
* FE_DISEQC_RECV_SLAVE_REPLY ioctl (only Satellite) * FE_DISEQC_RECV_SLAVE_REPLY() ioctl (only Satellite)
* @diseqc_send_burst: callback function to implement the * @diseqc_send_burst: callback function to implement the
* FE_DISEQC_SEND_BURST ioctl (only Satellite). * FE_DISEQC_SEND_BURST() ioctl (only Satellite).
* @set_tone: callback function to implement the * @set_tone: callback function to implement the
* FE_SET_TONE ioctl (only Satellite). * FE_SET_TONE() ioctl (only Satellite).
* @set_voltage: callback function to implement the * @set_voltage: callback function to implement the
* FE_SET_VOLTAGE ioctl (only Satellite). * FE_SET_VOLTAGE() ioctl (only Satellite).
* @enable_high_lnb_voltage: callback function to implement the * @enable_high_lnb_voltage: callback function to implement the
* FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite). * FE_ENABLE_HIGH_LNB_VOLTAGE() ioctl (only Satellite).
* @dishnetwork_send_legacy_command: callback function to implement the * @dishnetwork_send_legacy_command: callback function to implement the
* FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite). * FE_DISHNETWORK_SEND_LEGACY_CMD() ioctl (only Satellite).
* Drivers should not use this, except when the DVB * Drivers should not use this, except when the DVB
* core emulation fails to provide proper support (e.g. * core emulation fails to provide proper support (e.g.
* if @set_voltage takes more than 8ms to work), and * if @set_voltage takes more than 8ms to work), and
@ -404,16 +434,12 @@ struct dtv_frontend_properties;
* @ts_bus_ctrl: callback function used to take control of the TS bus. * @ts_bus_ctrl: callback function used to take control of the TS bus.
* @set_lna: callback function to power on/off/auto the LNA. * @set_lna: callback function to power on/off/auto the LNA.
* @search: callback function used on some custom algo search algos. * @search: callback function used on some custom algo search algos.
* @tuner_ops: pointer to struct dvb_tuner_ops * @tuner_ops: pointer to &struct dvb_tuner_ops
* @analog_ops: pointer to struct analog_demod_ops * @analog_ops: pointer to &struct analog_demod_ops
* @set_property: callback function to allow the frontend to validade
* incoming properties. Should not be used on new drivers.
* @get_property: callback function to allow the frontend to override
* outcoming properties. Should not be used on new drivers.
*/ */
struct dvb_frontend_ops { struct dvb_frontend_ops {
struct dvb_frontend_info info; struct dvb_frontend_internal_info info;
u8 delsys[MAX_DELSYS]; u8 delsys[MAX_DELSYS];
@ -473,9 +499,6 @@ struct dvb_frontend_ops {
struct dvb_tuner_ops tuner_ops; struct dvb_tuner_ops tuner_ops;
struct analog_demod_ops analog_ops; struct analog_demod_ops analog_ops;
int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
u8 xbar[3]; u8 xbar[3];
}; };
@ -506,7 +529,7 @@ struct dvb_fe_events {
* @fec_inner: Forward error correction inner Code Rate * @fec_inner: Forward error correction inner Code Rate
* @transmission_mode: Transmission Mode * @transmission_mode: Transmission Mode
* @bandwidth_hz: Bandwidth, in Hz. A zero value means that userspace * @bandwidth_hz: Bandwidth, in Hz. A zero value means that userspace
* wants to autodetect. * wants to autodetect.
* @guard_interval: Guard Interval * @guard_interval: Guard Interval
* @hierarchy: Hierarchy * @hierarchy: Hierarchy
* @symbol_rate: Symbol Rate * @symbol_rate: Symbol Rate
@ -529,8 +552,8 @@ struct dvb_fe_events {
* @layer.interleaving: per layer interleaving. * @layer.interleaving: per layer interleaving.
* @stream_id: If different than zero, enable substream filtering, if * @stream_id: If different than zero, enable substream filtering, if
* hardware supports (DVB-S2 and DVB-T2). * hardware supports (DVB-S2 and DVB-T2).
* @scrambling_sequence_index: Carries the index of the DVB-S2 physical layer * @scrambling_sequence_index: Carries the index of the DVB-S2 physical layer
* scrambling sequence. * scrambling sequence.
* @atscmh_fic_ver: Version number of the FIC (Fast Information Channel) * @atscmh_fic_ver: Version number of the FIC (Fast Information Channel)
* signaling data (only ATSC-M/H) * signaling data (only ATSC-M/H)
* @atscmh_parade_id: Parade identification number (only ATSC-M/H) * @atscmh_parade_id: Parade identification number (only ATSC-M/H)
@ -554,7 +577,7 @@ struct dvb_fe_events {
* @lna: Power ON/OFF/AUTO the Linear Now-noise Amplifier (LNA) * @lna: Power ON/OFF/AUTO the Linear Now-noise Amplifier (LNA)
* @strength: DVBv5 API statistics: Signal Strength * @strength: DVBv5 API statistics: Signal Strength
* @cnr: DVBv5 API statistics: Signal to Noise ratio of the * @cnr: DVBv5 API statistics: Signal to Noise ratio of the
* (main) carrier * (main) carrier
* @pre_bit_error: DVBv5 API statistics: pre-Viterbi bit error count * @pre_bit_error: DVBv5 API statistics: pre-Viterbi bit error count
* @pre_bit_count: DVBv5 API statistics: pre-Viterbi bit count * @pre_bit_count: DVBv5 API statistics: pre-Viterbi bit count
* @post_bit_error: DVBv5 API statistics: post-Viterbi bit error count * @post_bit_error: DVBv5 API statistics: post-Viterbi bit error count
@ -575,15 +598,15 @@ struct dtv_frontend_properties {
enum fe_sec_voltage voltage; enum fe_sec_voltage voltage;
enum fe_sec_tone_mode sectone; enum fe_sec_tone_mode sectone;
enum fe_spectral_inversion inversion; enum fe_spectral_inversion inversion;
enum fe_code_rate fec_inner; enum fe_code_rate fec_inner;
enum fe_transmit_mode transmission_mode; enum fe_transmit_mode transmission_mode;
u32 bandwidth_hz; /* 0 = AUTO */ u32 bandwidth_hz; /* 0 = AUTO */
enum fe_guard_interval guard_interval; enum fe_guard_interval guard_interval;
enum fe_hierarchy hierarchy; enum fe_hierarchy hierarchy;
u32 symbol_rate; u32 symbol_rate;
enum fe_code_rate code_rate_HP; enum fe_code_rate code_rate_HP;
enum fe_code_rate code_rate_LP; enum fe_code_rate code_rate_LP;
enum fe_pilot pilot; enum fe_pilot pilot;
enum fe_rolloff rolloff; enum fe_rolloff rolloff;
@ -610,7 +633,7 @@ struct dtv_frontend_properties {
u32 stream_id; u32 stream_id;
/* Physical Layer Scrambling specifics */ /* Physical Layer Scrambling specifics */
u32 scrambling_sequence_index; u32 scrambling_sequence_index;
/* ATSC-MH specifics */ /* ATSC-MH specifics */
u8 atscmh_fic_ver; u8 atscmh_fic_ver;
@ -642,11 +665,6 @@ struct dtv_frontend_properties {
struct dtv_fe_stats post_bit_count; struct dtv_fe_stats post_bit_count;
struct dtv_fe_stats block_error; struct dtv_fe_stats block_error;
struct dtv_fe_stats block_count; struct dtv_fe_stats block_count;
/* private: */
/* Cache State */
u32 state;
}; };
#define DVB_FE_NO_EXIT 0 #define DVB_FE_NO_EXIT 0
@ -657,16 +675,16 @@ struct dtv_frontend_properties {
/** /**
* struct dvb_frontend - Frontend structure to be used on drivers. * struct dvb_frontend - Frontend structure to be used on drivers.
* *
* @refcount: refcount to keep track of struct dvb_frontend * @refcount: refcount to keep track of &struct dvb_frontend
* references * references
* @ops: embedded struct dvb_frontend_ops * @ops: embedded &struct dvb_frontend_ops
* @dvb: pointer to struct dvb_adapter * @dvb: pointer to &struct dvb_adapter
* @demodulator_priv: demod private data * @demodulator_priv: demod private data
* @tuner_priv: tuner private data * @tuner_priv: tuner private data
* @frontend_priv: frontend private data * @frontend_priv: frontend private data
* @sec_priv: SEC private data * @sec_priv: SEC private data
* @analog_demod_priv: Analog demod private data * @analog_demod_priv: Analog demod private data
* @dtv_property_cache: embedded struct dtv_frontend_properties * @dtv_property_cache: embedded &struct dtv_frontend_properties
* @callback: callback function used on some drivers to call * @callback: callback function used on some drivers to call
* either the tuner or the demodulator. * either the tuner or the demodulator.
* @id: Frontend ID * @id: Frontend ID
@ -695,8 +713,8 @@ struct dvb_frontend {
/** /**
* dvb_register_frontend() - Registers a DVB frontend at the adapter * dvb_register_frontend() - Registers a DVB frontend at the adapter
* *
* @dvb: pointer to the dvb adapter * @dvb: pointer to &struct dvb_adapter
* @fe: pointer to the frontend struct * @fe: pointer to &struct dvb_frontend
* *
* Allocate and initialize the private data needed by the frontend core to * Allocate and initialize the private data needed by the frontend core to
* manage the frontend and calls dvb_register_device() to register a new * manage the frontend and calls dvb_register_device() to register a new
@ -709,7 +727,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb,
/** /**
* dvb_unregister_frontend() - Unregisters a DVB frontend * dvb_unregister_frontend() - Unregisters a DVB frontend
* *
* @fe: pointer to the frontend struct * @fe: pointer to &struct dvb_frontend
* *
* Stops the frontend kthread, calls dvb_unregister_device() and frees the * Stops the frontend kthread, calls dvb_unregister_device() and frees the
* private frontend data allocated by dvb_register_frontend(). * private frontend data allocated by dvb_register_frontend().
@ -723,14 +741,14 @@ int dvb_unregister_frontend(struct dvb_frontend *fe);
/** /**
* dvb_frontend_detach() - Detaches and frees frontend specific data * dvb_frontend_detach() - Detaches and frees frontend specific data
* *
* @fe: pointer to the frontend struct * @fe: pointer to &struct dvb_frontend
* *
* This function should be called after dvb_unregister_frontend(). It * This function should be called after dvb_unregister_frontend(). It
* calls the SEC, tuner and demod release functions: * calls the SEC, tuner and demod release functions:
* &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release, * &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release,
* &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release. * &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release.
* *
* If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases * If the driver is compiled with %CONFIG_MEDIA_ATTACH, it also decreases
* the module reference count, needed to allow userspace to remove the * the module reference count, needed to allow userspace to remove the
* previously used DVB frontend modules. * previously used DVB frontend modules.
*/ */
@ -739,7 +757,7 @@ void dvb_frontend_detach(struct dvb_frontend *fe);
/** /**
* dvb_frontend_suspend() - Suspends a Digital TV frontend * dvb_frontend_suspend() - Suspends a Digital TV frontend
* *
* @fe: pointer to the frontend struct * @fe: pointer to &struct dvb_frontend
* *
* This function prepares a Digital TV frontend to suspend. * This function prepares a Digital TV frontend to suspend.
* *
@ -757,7 +775,7 @@ int dvb_frontend_suspend(struct dvb_frontend *fe);
/** /**
* dvb_frontend_resume() - Resumes a Digital TV frontend * dvb_frontend_resume() - Resumes a Digital TV frontend
* *
* @fe: pointer to the frontend struct * @fe: pointer to &struct dvb_frontend
* *
* This function resumes the usual operation of the tuner after resume. * This function resumes the usual operation of the tuner after resume.
* *
@ -778,7 +796,7 @@ int dvb_frontend_resume(struct dvb_frontend *fe);
/** /**
* dvb_frontend_reinitialise() - forces a reinitialisation at the frontend * dvb_frontend_reinitialise() - forces a reinitialisation at the frontend
* *
* @fe: pointer to the frontend struct * @fe: pointer to &struct dvb_frontend
* *
* Calls &dvb_frontend_ops.init\(\) and &dvb_frontend_ops.tuner_ops.init\(\), * Calls &dvb_frontend_ops.init\(\) and &dvb_frontend_ops.tuner_ops.init\(\),
* and resets SEC tone and voltage (for Satellite systems). * and resets SEC tone and voltage (for Satellite systems).
@ -793,16 +811,16 @@ void dvb_frontend_reinitialise(struct dvb_frontend *fe);
* dvb_frontend_sleep_until() - Sleep for the amount of time given by * dvb_frontend_sleep_until() - Sleep for the amount of time given by
* add_usec parameter * add_usec parameter
* *
* @waketime: pointer to a struct ktime_t * @waketime: pointer to &struct ktime_t
* @add_usec: time to sleep, in microseconds * @add_usec: time to sleep, in microseconds
* *
* This function is used to measure the time required for the * This function is used to measure the time required for the
* %FE_DISHNETWORK_SEND_LEGACY_CMD ioctl to work. It needs to be as precise * FE_DISHNETWORK_SEND_LEGACY_CMD() ioctl to work. It needs to be as precise
* as possible, as it affects the detection of the dish tone command at the * as possible, as it affects the detection of the dish tone command at the
* satellite subsystem. * satellite subsystem.
* *
* Its used internally by the DVB frontend core, in order to emulate * Its used internally by the DVB frontend core, in order to emulate
* %FE_DISHNETWORK_SEND_LEGACY_CMD using the &dvb_frontend_ops.set_voltage\(\) * FE_DISHNETWORK_SEND_LEGACY_CMD() using the &dvb_frontend_ops.set_voltage\(\)
* callback. * callback.
* *
* NOTE: it should not be used at the drivers, as the emulation for the * NOTE: it should not be used at the drivers, as the emulation for the

View File

@ -24,12 +24,28 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include "dvbdev.h" #include <media/dvbdev.h>
#define DVB_NET_DEVICES_MAX 10 #define DVB_NET_DEVICES_MAX 10
#ifdef CONFIG_DVB_NET #ifdef CONFIG_DVB_NET
/**
* struct dvb_net - describes a DVB network interface
*
* @dvbdev: pointer to &struct dvb_device.
* @device: array of pointers to &struct net_device.
* @state: array of integers to each net device. A value
* different than zero means that the interface is
* in usage.
* @exit: flag to indicate when the device is being removed.
* @demux: pointer to &struct dmx_demux.
* @ioctl_mutex: protect access to this struct.
*
* Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network
* devices.
*/
struct dvb_net { struct dvb_net {
struct dvb_device *dvbdev; struct dvb_device *dvbdev;
struct net_device *device[DVB_NET_DEVICES_MAX]; struct net_device *device[DVB_NET_DEVICES_MAX];
@ -39,8 +55,22 @@ struct dvb_net {
struct mutex ioctl_mutex; struct mutex ioctl_mutex;
}; };
void dvb_net_release(struct dvb_net *); /**
int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *); * dvb_net_init - nitializes a digital TV network device and registers it.
*
* @adap: pointer to &struct dvb_adapter.
* @dvbnet: pointer to &struct dvb_net.
* @dmxdemux: pointer to &struct dmx_demux.
*/
int dvb_net_init(struct dvb_adapter *adap, struct dvb_net *dvbnet,
struct dmx_demux *dmxdemux);
/**
* dvb_net_release - releases a digital TV network device and unregisters it.
*
* @dvbnet: pointer to &struct dvb_net.
*/
void dvb_net_release(struct dvb_net *dvbnet);
#else #else

View File

@ -0,0 +1,280 @@
/*
* SPDX-License-Identifier: GPL-2.0
*
* dvb-vb2.h - DVB driver helper framework for streaming I/O
*
* Copyright (C) 2015 Samsung Electronics
*
* Author: jh1009.sung@samsung.com
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation.
*/
#ifndef _DVB_VB2_H
#define _DVB_VB2_H
#include <linux/mutex.h>
#include <linux/poll.h>
#include <linux/dvb/dmx.h>
#include <media/videobuf2-core.h>
#include <media/videobuf2-dma-contig.h>
#include <media/videobuf2-vmalloc.h>
/**
* enum dvb_buf_type - types of Digital TV memory-mapped buffers
*
* @DVB_BUF_TYPE_CAPTURE: buffer is filled by the Kernel,
* with a received Digital TV stream
*/
enum dvb_buf_type {
DVB_BUF_TYPE_CAPTURE = 1,
};
/**
* enum dvb_vb2_states - states to control VB2 state machine
* @DVB_VB2_STATE_NONE:
* VB2 engine not initialized yet, init failed or VB2 was released.
* @DVB_VB2_STATE_INIT:
* VB2 engine initialized.
* @DVB_VB2_STATE_REQBUFS:
* Buffers were requested
* @DVB_VB2_STATE_STREAMON:
* VB2 is streaming. Callers should not check it directly. Instead,
* they should use dvb_vb2_is_streaming().
*
* Note:
*
* Callers should not touch at the state machine directly. This
* is handled inside dvb_vb2.c.
*/
enum dvb_vb2_states {
DVB_VB2_STATE_NONE = 0x0,
DVB_VB2_STATE_INIT = 0x1,
DVB_VB2_STATE_REQBUFS = 0x2,
DVB_VB2_STATE_STREAMON = 0x4,
};
#define DVB_VB2_NAME_MAX (20)
/**
* struct dvb_buffer - video buffer information for v4l2.
*
* @vb: embedded struct &vb2_buffer.
* @list: list of &struct dvb_buffer.
*/
struct dvb_buffer {
struct vb2_buffer vb;
struct list_head list;
};
/**
* struct dvb_vb2_ctx - control struct for VB2 handler
* @vb_q: pointer to &struct vb2_queue with videobuf2 queue.
* @mutex: mutex to serialize vb2 operations. Used by
* vb2 core %wait_prepare and %wait_finish operations.
* @slock: spin lock used to protect buffer filling at dvb_vb2.c.
* @dvb_q: List of buffers that are not filled yet.
* @buf: Pointer to the buffer that are currently being filled.
* @offset: index to the next position at the @buf to be filled.
* @remain: How many bytes are left to be filled at @buf.
* @state: bitmask of buffer states as defined by &enum dvb_vb2_states.
* @buf_siz: size of each VB2 buffer.
* @buf_cnt: number of VB2 buffers.
* @nonblocking:
* If different than zero, device is operating on non-blocking
* mode.
* @flags: buffer flags as defined by &enum dmx_buffer_flags.
* Filled only at &DMX_DQBUF. &DMX_QBUF should zero this field.
* @count: monotonic counter for filled buffers. Helps to identify
* data stream loses. Filled only at &DMX_DQBUF. &DMX_QBUF should
* zero this field.
*
* @name: name of the device type. Currently, it can either be
* "dvr" or "demux_filter".
*/
struct dvb_vb2_ctx {
struct vb2_queue vb_q;
struct mutex mutex;
spinlock_t slock;
struct list_head dvb_q;
struct dvb_buffer *buf;
int offset;
int remain;
int state;
int buf_siz;
int buf_cnt;
int nonblocking;
enum dmx_buffer_flags flags;
u32 count;
char name[DVB_VB2_NAME_MAX + 1];
};
#ifndef CONFIG_DVB_MMAP
static inline int dvb_vb2_init(struct dvb_vb2_ctx *ctx,
const char *name, int non_blocking)
{
return 0;
};
static inline int dvb_vb2_release(struct dvb_vb2_ctx *ctx)
{
return 0;
};
#define dvb_vb2_is_streaming(ctx) (0)
#define dvb_vb2_fill_buffer(ctx, file, wait, flags) (0)
static inline __poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx,
struct file *file,
poll_table *wait)
{
return 0;
}
#else
/**
* dvb_vb2_init - initializes VB2 handler
*
* @ctx: control struct for VB2 handler
* @name: name for the VB2 handler
* @non_blocking:
* if not zero, it means that the device is at non-blocking mode
*/
int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int non_blocking);
/**
* dvb_vb2_release - Releases the VB2 handler allocated resources and
* put @ctx at DVB_VB2_STATE_NONE state.
* @ctx: control struct for VB2 handler
*/
int dvb_vb2_release(struct dvb_vb2_ctx *ctx);
/**
* dvb_vb2_is_streaming - checks if the VB2 handler is streaming
* @ctx: control struct for VB2 handler
*
* Return: 0 if not streaming, 1 otherwise.
*/
int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx);
/**
* dvb_vb2_fill_buffer - fills a VB2 buffer
* @ctx: control struct for VB2 handler
* @src: place where the data is stored
* @len: number of bytes to be copied from @src
* @buffer_flags:
* pointer to buffer flags as defined by &enum dmx_buffer_flags.
* can be NULL.
*/
int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx,
const unsigned char *src, int len,
enum dmx_buffer_flags *buffer_flags);
/**
* dvb_vb2_poll - Wrapper to vb2_core_streamon() for Digital TV
* buffer handling.
*
* @ctx: control struct for VB2 handler
* @file: &struct file argument passed to the poll
* file operation handler.
* @wait: &poll_table wait argument passed to the poll
* file operation handler.
*
* Implements poll syscall() logic.
*/
__poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx, struct file *file,
poll_table *wait);
#endif
/**
* dvb_vb2_stream_on() - Wrapper to vb2_core_streamon() for Digital TV
* buffer handling.
*
* @ctx: control struct for VB2 handler
*
* Starts dvb streaming
*/
int dvb_vb2_stream_on(struct dvb_vb2_ctx *ctx);
/**
* dvb_vb2_stream_off() - Wrapper to vb2_core_streamoff() for Digital TV
* buffer handling.
*
* @ctx: control struct for VB2 handler
*
* Stops dvb streaming
*/
int dvb_vb2_stream_off(struct dvb_vb2_ctx *ctx);
/**
* dvb_vb2_reqbufs() - Wrapper to vb2_core_reqbufs() for Digital TV
* buffer handling.
*
* @ctx: control struct for VB2 handler
* @req: &struct dmx_requestbuffers passed from userspace in
* order to handle &DMX_REQBUFS.
*
* Initiate streaming by requesting a number of buffers. Also used to
* free previously requested buffers, is ``req->count`` is zero.
*/
int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req);
/**
* dvb_vb2_querybuf() - Wrapper to vb2_core_querybuf() for Digital TV
* buffer handling.
*
* @ctx: control struct for VB2 handler
* @b: &struct dmx_buffer passed from userspace in
* order to handle &DMX_QUERYBUF.
*
*
*/
int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b);
/**
* dvb_vb2_expbuf() - Wrapper to vb2_core_expbuf() for Digital TV
* buffer handling.
*
* @ctx: control struct for VB2 handler
* @exp: &struct dmx_exportbuffer passed from userspace in
* order to handle &DMX_EXPBUF.
*
* Export a buffer as a file descriptor.
*/
int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp);
/**
* dvb_vb2_qbuf() - Wrapper to vb2_core_qbuf() for Digital TV buffer handling.
*
* @ctx: control struct for VB2 handler
* @b: &struct dmx_buffer passed from userspace in
* order to handle &DMX_QBUF.
*
* Queue a Digital TV buffer as requested by userspace
*/
int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b);
/**
* dvb_vb2_dqbuf() - Wrapper to vb2_core_dqbuf() for Digital TV
* buffer handling.
*
* @ctx: control struct for VB2 handler
* @b: &struct dmx_buffer passed from userspace in
* order to handle &DMX_DQBUF.
*
* Dequeue a Digital TV buffer to the userspace
*/
int dvb_vb2_dqbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b);
/**
* dvb_vb2_mmap() - Wrapper to vb2_mmap() for Digital TV buffer handling.
*
* @ctx: control struct for VB2 handler
* @vma: pointer to &struct vm_area_struct with the vma passed
* to the mmap file operation handler in the driver.
*
* map Digital TV video buffers into application address space.
*/
int dvb_vb2_mmap(struct dvb_vb2_ctx *ctx, struct vm_area_struct *vma);
#endif /* _DVB_VB2_H */

View File

@ -35,19 +35,42 @@
#define DVB_UNSET (-1) #define DVB_UNSET (-1)
#define DVB_DEVICE_VIDEO 0 /* List of DVB device types */
#define DVB_DEVICE_AUDIO 1
#define DVB_DEVICE_SEC 2 /**
#define DVB_DEVICE_FRONTEND 3 * enum dvb_device_type - type of the Digital TV device
#define DVB_DEVICE_DEMUX 4 *
#define DVB_DEVICE_DVR 5 * @DVB_DEVICE_SEC: Digital TV standalone Common Interface (CI)
#define DVB_DEVICE_CA 6 * @DVB_DEVICE_FRONTEND: Digital TV frontend.
#define DVB_DEVICE_NET 7 * @DVB_DEVICE_DEMUX: Digital TV demux.
#define DVB_DEVICE_OSD 8 * @DVB_DEVICE_DVR: Digital TV digital video record (DVR).
#define DVB_DEVICE_CI 9 * @DVB_DEVICE_CA: Digital TV Conditional Access (CA).
#define DVB_DEVICE_MOD 10 * @DVB_DEVICE_NET: Digital TV network.
#define DVB_DEVICE_NS 11 *
#define DVB_DEVICE_NSD 12 * @DVB_DEVICE_VIDEO: Digital TV video decoder.
* Deprecated. Used only on av7110-av.
* @DVB_DEVICE_AUDIO: Digital TV audio decoder.
* Deprecated. Used only on av7110-av.
* @DVB_DEVICE_OSD: Digital TV On Screen Display (OSD).
* Deprecated. Used only on av7110.
*/
enum dvb_device_type {
DVB_DEVICE_SEC,
DVB_DEVICE_FRONTEND,
DVB_DEVICE_DEMUX,
DVB_DEVICE_DVR,
DVB_DEVICE_CA,
DVB_DEVICE_NET,
DVB_DEVICE_VIDEO,
DVB_DEVICE_AUDIO,
DVB_DEVICE_OSD,
DVB_DEVICE_CI,
DVB_DEVICE_MOD,
DVB_DEVICE_NS,
DVB_DEVICE_NSD,
};
#define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \ #define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \
static short adapter_nr[] = \ static short adapter_nr[] = \
@ -68,11 +91,12 @@ struct dvb_frontend;
* @priv: private data * @priv: private data
* @device: pointer to struct device * @device: pointer to struct device
* @module: pointer to struct module * @module: pointer to struct module
* @mfe_shared: mfe shared: indicates mutually exclusive frontends * @mfe_shared: indicates mutually exclusive frontends.
* Thie usage of this flag is currently deprecated * Use of this flag is currently deprecated.
* @mfe_dvbdev: Frontend device in use, in the case of MFE * @mfe_dvbdev: Frontend device in use, in the case of MFE
* @mfe_lock: Lock to prevent using the other frontends when MFE is * @mfe_lock: Lock to prevent using the other frontends when MFE is
* used. * used.
* @mdev_lock: Protect access to the mdev pointer.
* @mdev: pointer to struct media_device, used when the media * @mdev: pointer to struct media_device, used when the media
* controller is used. * controller is used.
* @conn: RF connector. Used only if the device has no separate * @conn: RF connector. Used only if the device has no separate
@ -96,6 +120,7 @@ struct dvb_adapter {
struct mutex mfe_lock; /* access lock for thread creation */ struct mutex mfe_lock; /* access lock for thread creation */
#if defined(CONFIG_MEDIA_CONTROLLER_DVB) #if defined(CONFIG_MEDIA_CONTROLLER_DVB)
struct mutex mdev_lock;
struct media_device *mdev; struct media_device *mdev;
struct media_entity *conn; struct media_entity *conn;
struct media_pad *conn_pads; struct media_pad *conn_pads;
@ -108,8 +133,7 @@ struct dvb_adapter {
* @list_head: List head with all DVB devices * @list_head: List head with all DVB devices
* @fops: pointer to struct file_operations * @fops: pointer to struct file_operations
* @adapter: pointer to the adapter that holds this device node * @adapter: pointer to the adapter that holds this device node
* @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND, * @type: type of the device, as defined by &enum dvb_device_type.
* DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET
* @minor: devnode minor number. Major number is always DVB_MAJOR. * @minor: devnode minor number. Major number is always DVB_MAJOR.
* @id: device ID number, inside the adapter * @id: device ID number, inside the adapter
* @readers: Initialized by the caller. Each call to open() in Read Only mode * @readers: Initialized by the caller. Each call to open() in Read Only mode
@ -139,7 +163,7 @@ struct dvb_device {
struct list_head list_head; struct list_head list_head;
const struct file_operations *fops; const struct file_operations *fops;
struct dvb_adapter *adapter; struct dvb_adapter *adapter;
int type; enum dvb_device_type type;
int minor; int minor;
u32 id; u32 id;
@ -176,7 +200,7 @@ struct dvb_device {
* @module: initialized with THIS_MODULE at the caller * @module: initialized with THIS_MODULE at the caller
* @device: pointer to struct device that corresponds to the device driver * @device: pointer to struct device that corresponds to the device driver
* @adapter_nums: Array with a list of the numbers for @dvb_register_adapter; * @adapter_nums: Array with a list of the numbers for @dvb_register_adapter;
* to select among them. Typically, initialized with: * to select among them. Typically, initialized with:
* DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums) * DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums)
*/ */
int dvb_register_adapter(struct dvb_adapter *adap, const char *name, int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
@ -198,9 +222,7 @@ int dvb_unregister_adapter(struct dvb_adapter *adap);
* stored * stored
* @template: Template used to create &pdvbdev; * @template: Template used to create &pdvbdev;
* @priv: private data * @priv: private data
* @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND, * @type: type of the device, as defined by &enum dvb_device_type.
* %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA,
* %DVB_DEVICE_NET
* @demux_sink_pads: Number of demux outputs, to be used to create the TS * @demux_sink_pads: Number of demux outputs, to be used to create the TS
* outputs via the Media Controller. * outputs via the Media Controller.
*/ */
@ -208,7 +230,7 @@ int dvb_register_device(struct dvb_adapter *adap,
struct dvb_device **pdvbdev, struct dvb_device **pdvbdev,
const struct dvb_device *template, const struct dvb_device *template,
void *priv, void *priv,
int type, enum dvb_device_type type,
int demux_sink_pads); int demux_sink_pads);
/** /**
@ -244,9 +266,9 @@ void dvb_unregister_device(struct dvb_device *dvbdev);
#ifdef CONFIG_MEDIA_CONTROLLER_DVB #ifdef CONFIG_MEDIA_CONTROLLER_DVB
/** /**
* dvb_create_media_graph - Creates media graph for the Digital TV part of the * dvb_create_media_graph - Creates media graph for the Digital TV part of the
* device. * device.
* *
* @adap: pointer to struct dvb_adapter * @adap: pointer to &struct dvb_adapter
* @create_rf_connector: if true, it creates the RF connector too * @create_rf_connector: if true, it creates the RF connector too
* *
* This function checks all DVB-related functions at the media controller * This function checks all DVB-related functions at the media controller
@ -259,14 +281,25 @@ void dvb_unregister_device(struct dvb_device *dvbdev);
__must_check int dvb_create_media_graph(struct dvb_adapter *adap, __must_check int dvb_create_media_graph(struct dvb_adapter *adap,
bool create_rf_connector); bool create_rf_connector);
/**
* dvb_register_media_controller - registers a media controller at DVB adapter
*
* @adap: pointer to &struct dvb_adapter
* @mdev: pointer to &struct media_device
*/
static inline void dvb_register_media_controller(struct dvb_adapter *adap, static inline void dvb_register_media_controller(struct dvb_adapter *adap,
struct media_device *mdev) struct media_device *mdev)
{ {
adap->mdev = mdev; adap->mdev = mdev;
} }
static inline struct media_device /**
*dvb_get_media_controller(struct dvb_adapter *adap) * dvb_get_media_controller - gets the associated media controller
*
* @adap: pointer to &struct dvb_adapter
*/
static inline struct media_device *
dvb_get_media_controller(struct dvb_adapter *adap)
{ {
return adap->mdev; return adap->mdev;
} }
@ -281,20 +314,131 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
#define dvb_get_media_controller(a) NULL #define dvb_get_media_controller(a) NULL
#endif #endif
int dvb_generic_open (struct inode *inode, struct file *file); /**
int dvb_generic_release (struct inode *inode, struct file *file); * dvb_generic_open - Digital TV open function, used by DVB devices
long dvb_generic_ioctl (struct file *file, *
unsigned int cmd, unsigned long arg); * @inode: pointer to &struct inode.
* @file: pointer to &struct file.
*
* Checks if a DVB devnode is still valid, and if the permissions are
* OK and increment negative use count.
*/
int dvb_generic_open(struct inode *inode, struct file *file);
/* we don't mess with video_usercopy() any more, /**
we simply define out own dvb_usercopy(), which will hopefully become * dvb_generic_close - Digital TV close function, used by DVB devices
generic_usercopy() someday... */ *
* @inode: pointer to &struct inode.
* @file: pointer to &struct file.
*
* Checks if a DVB devnode is still valid, and if the permissions are
* OK and decrement negative use count.
*/
int dvb_generic_release(struct inode *inode, struct file *file);
/**
* dvb_generic_ioctl - Digital TV close function, used by DVB devices
*
* @file: pointer to &struct file.
* @cmd: Ioctl name.
* @arg: Ioctl argument.
*
* Checks if a DVB devnode and struct dvbdev.kernel_ioctl is still valid.
* If so, calls dvb_usercopy().
*/
long dvb_generic_ioctl(struct file *file,
unsigned int cmd, unsigned long arg);
/**
* dvb_usercopy - copies data from/to userspace memory when an ioctl is
* issued.
*
* @file: Pointer to struct &file.
* @cmd: Ioctl name.
* @arg: Ioctl argument.
* @func: function that will actually handle the ioctl
*
* Ancillary function that uses ioctl direction and size to copy from
* userspace. Then, it calls @func, and, if needed, data is copied back
* to userspace.
*/
int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
int (*func)(struct file *file, unsigned int cmd, void *arg)); int (*func)(struct file *file, unsigned int cmd, void *arg));
/** generic DVB attach function. */ #if IS_ENABLED(CONFIG_I2C)
struct i2c_adapter;
struct i2c_client;
/**
* dvb_module_probe - helper routine to probe an I2C module
*
* @module_name:
* Name of the I2C module to be probed
* @name:
* Optional name for the I2C module. Used for debug purposes.
* If %NULL, defaults to @module_name.
* @adap:
* pointer to &struct i2c_adapter that describes the I2C adapter where
* the module will be bound.
* @addr:
* I2C address of the adapter, in 7-bit notation.
* @platform_data:
* Platform data to be passed to the I2C module probed.
*
* This function binds an I2C device into the DVB core. Should be used by
* all drivers that use I2C bus to control the hardware. A module bound
* with dvb_module_probe() should use dvb_module_release() to unbind.
*
* Return:
* On success, return an &struct i2c_client, pointing to the bound
* I2C device. %NULL otherwise.
*
* .. note::
*
* In the past, DVB modules (mainly, frontends) were bound via dvb_attach()
* macro, with does an ugly hack, using I2C low level functions. Such
* usage is deprecated and will be removed soon. Instead, use this routine.
*/
struct i2c_client *dvb_module_probe(const char *module_name,
const char *name,
struct i2c_adapter *adap,
unsigned char addr,
void *platform_data);
/**
* dvb_module_release - releases an I2C device allocated with
* dvb_module_probe().
*
* @client: pointer to &struct i2c_client with the I2C client to be released.
* can be %NULL.
*
* This function should be used to free all resources reserved by
* dvb_module_probe() and unbinding the I2C hardware.
*/
void dvb_module_release(struct i2c_client *client);
#endif /* CONFIG_I2C */
/* Legacy generic DVB attach function. */
#ifdef CONFIG_MEDIA_ATTACH #ifdef CONFIG_MEDIA_ATTACH
/**
* dvb_attach - attaches a DVB frontend into the DVB core.
*
* @FUNCTION: function on a frontend module to be called.
* @ARGS...: @FUNCTION arguments.
*
* This ancillary function loads a frontend module in runtime and runs
* the @FUNCTION function there, with @ARGS.
* As it increments symbol usage cont, at unregister, dvb_detach()
* should be called.
*
* .. note::
*
* In the past, DVB modules (mainly, frontends) were bound via dvb_attach()
* macro, with does an ugly hack, using I2C low level functions. Such
* usage is deprecated and will be removed soon. Instead, you should use
* dvb_module_probe().
*/
#define dvb_attach(FUNCTION, ARGS...) ({ \ #define dvb_attach(FUNCTION, ARGS...) ({ \
void *__r = NULL; \ void *__r = NULL; \
typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
@ -308,6 +452,14 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
__r; \ __r; \
}) })
/**
* dvb_detach - detaches a DVB frontend loaded via dvb_attach()
*
* @FUNC: attach function
*
* Decrements usage count for a function previously called via dvb_attach().
*/
#define dvb_detach(FUNC) symbol_put_addr(FUNC) #define dvb_detach(FUNC) symbol_put_addr(FUNC)
#else #else
@ -317,6 +469,6 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
#define dvb_detach(FUNC) {} #define dvb_detach(FUNC) {}
#endif #endif /* CONFIG_MEDIA_ATTACH */
#endif /* #ifndef _DVBDEV_H_ */ #endif /* #ifndef _DVBDEV_H_ */