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:
parent
83f5b45928
commit
7f19a0c04b
10
Makefile
10
Makefile
@ -2,10 +2,15 @@ kernelver ?= $(shell uname -r)
|
||||
KDIR ?= /lib/modules/$(kernelver)/build
|
||||
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:
|
||||
$(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) $(MODDEFS) modules
|
||||
$(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) $(MODDEFS) modules NOSTDINC_FLAGS=$(DDDVB_INC)
|
||||
$(MAKE) -C apps
|
||||
|
||||
libdddvb:
|
||||
@ -22,6 +27,7 @@ dep:
|
||||
|
||||
install: all
|
||||
$(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) modules_install
|
||||
depmod -a
|
||||
|
||||
clean:
|
||||
rm -rf */.*.o.d */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules*
|
||||
|
@ -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
|
||||
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
|
||||
|
||||
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends
|
||||
EXTRA_CFLAGS += -Idrivers/media/common/tuners
|
||||
NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core
|
||||
#EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends
|
||||
#EXTRA_CFLAGS += -Idrivers/media/common/tuners
|
||||
#NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core
|
@ -1,14 +1,15 @@
|
||||
#
|
||||
# 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
|
||||
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_OCTONET) += octonet.o
|
||||
|
||||
ccflags-y += -Idrivers/media/dvb-core/
|
||||
ccflags-y += -Idrivers/media/dvb-frontends/
|
||||
ccflags-y += -Idrivers/media/tuners/
|
||||
|
||||
#ccflags-y += -Idrivers/media/include/linux/
|
||||
#ccflags-y += -Idrivers/media/dvb-frontends/
|
||||
#ccflags-y += -Idrivers/media/tuners/
|
||||
|
@ -24,7 +24,7 @@
|
||||
#include "ddbridge.h"
|
||||
#include "ddbridge-i2c.h"
|
||||
#include "ddbridge-io.h"
|
||||
#include "dvb_net.h"
|
||||
#include <media/dvb_net.h>
|
||||
|
||||
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;
|
||||
return irq;
|
||||
}
|
||||
EXPORT_SYMBOL(ddb_irq_set);
|
||||
|
||||
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)
|
||||
ddbwritel(dev, con | 1, TS_CONTROL(output));
|
||||
if (output->dma) {
|
||||
if (output->dma)
|
||||
output->dma->running = 1;
|
||||
}
|
||||
}
|
||||
|
||||
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 + 1) % output->dma->num) == idx) &&
|
||||
(output->dma->size - output->dma->coff <= 2*188))
|
||||
(output->dma->size - output->dma->coff <= 2 * 188))
|
||||
return 0;
|
||||
return 188;
|
||||
}
|
||||
@ -679,25 +679,6 @@ static u32 ddb_output_free(struct ddb_output *output)
|
||||
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,
|
||||
const __user u8 *buf, size_t count)
|
||||
{
|
||||
@ -753,79 +734,6 @@ static ssize_t ddb_output_write(struct ddb_output *output,
|
||||
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)
|
||||
{
|
||||
struct ddb *dev = input->port->dev;
|
||||
@ -1125,9 +1033,9 @@ static struct dvb_frontend_ops dummy_ops = {
|
||||
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBS, SYS_DVBS2 },
|
||||
.info = {
|
||||
.name = "DUMMY DVB-C/C2 DVB-T/T2",
|
||||
.frequency_stepsize = 166667, /* DVB-T only */
|
||||
.frequency_min = 47000000, /* DVB-T: 47125000 */
|
||||
.frequency_max = 865000000, /* DVB-C: 862000000 */
|
||||
.frequency_stepsize_hz = 166667, /* DVB-T only */
|
||||
.frequency_min_hz = 47000000, /* DVB-T: 47125000 */
|
||||
.frequency_max_hz = 865000000, /* DVB-C: 862000000 */
|
||||
.symbol_rate_min = 870000,
|
||||
.symbol_rate_max = 11700000,
|
||||
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
|
||||
@ -1484,29 +1392,6 @@ static int tuner_attach_stv6111(struct ddb_input *input, int type)
|
||||
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)
|
||||
{
|
||||
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 ||
|
||||
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];
|
||||
adap = port->dvb[0].adap;
|
||||
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;
|
||||
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) {
|
||||
port->name = "DUAL DVB-S2 MAX";
|
||||
port->type_name = "MXL5XX";
|
||||
@ -2447,17 +2322,15 @@ static void input_tasklet(unsigned long data)
|
||||
dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma));
|
||||
dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma));
|
||||
|
||||
#if 1
|
||||
{
|
||||
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 = ((packet_loss & 0xFFFF0000) | cur_counter);
|
||||
packet_loss = ((packet_loss & 0xffff0000) | cur_counter);
|
||||
dma->packet_loss = packet_loss;
|
||||
}
|
||||
#endif
|
||||
if (4 & dma->ctrl)
|
||||
dma->stall_count++;
|
||||
if (input->redi)
|
||||
@ -2468,7 +2341,7 @@ static void input_tasklet(unsigned long data)
|
||||
spin_unlock_irqrestore(&dma->lock, flags);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifdef OPTIMIZE_TASKLETS
|
||||
static void input_handler(unsigned long data)
|
||||
{
|
||||
struct ddb_input *input = (struct ddb_input *)data;
|
||||
@ -2530,7 +2403,7 @@ unlock_exit:
|
||||
spin_unlock_irqrestore(&dma->lock, flags);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifdef OPTIMIZE_TASKLETS
|
||||
static void output_handler(void *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;
|
||||
}
|
||||
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)
|
||||
@ -2648,10 +2517,6 @@ static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr)
|
||||
if (port->lnr)
|
||||
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_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);
|
||||
output->regs = DDB_LINK_TAG(port->lnr) |
|
||||
(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) {
|
||||
const struct ddb_regmap *rm0 = io_regmap(output, 0);
|
||||
u32 base = rm0->irq_base_odma;
|
||||
@ -3683,7 +3544,7 @@ static ssize_t temp_show(struct device *device,
|
||||
l = attr->attr.name[5] - 0x30;
|
||||
link = &dev->link[l];
|
||||
|
||||
if (link->info->type == DDB_MOD ) {
|
||||
if (link->info->type == DDB_MOD) {
|
||||
if (link->info->version >= 2) {
|
||||
temp = 0xffff & ddbreadl(dev, TEMPMON2_BOARD);
|
||||
temp = (temp * 1000) >> 8;
|
||||
@ -3755,25 +3616,6 @@ static ssize_t ctemp_show(struct device *device,
|
||||
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,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -3954,32 +3796,6 @@ static ssize_t redirect_store(struct device *device,
|
||||
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,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
@ -4137,9 +3953,6 @@ static struct device_attribute ddb_attrs[] = {
|
||||
__ATTR_MRO(devid3, devid_show),
|
||||
__ATTR_RO(hwid),
|
||||
__ATTR_RO(regmap),
|
||||
#if 0
|
||||
__ATTR_RO(qam),
|
||||
#endif
|
||||
__ATTR(redirect, 0664, redirect_show, redirect_store),
|
||||
__ATTR_MRO(snr, bsnr_show),
|
||||
__ATTR_RO(bpsnr),
|
||||
@ -4239,7 +4052,6 @@ static void ddb_device_attrs_del(struct ddb *dev)
|
||||
if (dev->link[i].info &&
|
||||
dev->link[i].info->temp_num)
|
||||
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++)
|
||||
device_remove_file(dev->ddb_dev, &ddb_attrs_mod[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)
|
||||
{
|
||||
struct ddb_link *link = (struct ddb_link *)priv;
|
||||
#if 1
|
||||
#ifdef USE_LINK_TASKLET
|
||||
tasklet_schedule(&link->tasklet);
|
||||
#else
|
||||
struct ddb *dev = link->dev;
|
||||
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, 24);
|
||||
}
|
||||
#else
|
||||
tasklet_schedule(&link->tasklet);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -4434,7 +4246,7 @@ static int ddb_gtl_init_link(struct ddb *dev, u32 l)
|
||||
subid & 0xffff, subid >> 16);
|
||||
if (link->info->type != DDB_OCTOPUS_MAX_CT &&
|
||||
link->info->type != DDB_OCTOPUS_MAX &&
|
||||
link->info->type != DDB_OCTOPUS_MCI ) {
|
||||
link->info->type != DDB_OCTOPUS_MCI) {
|
||||
dev_info(dev->dev,
|
||||
"Detected GT link but found invalid ID %08x. You might have to update (flash) the add-on card first.",
|
||||
id);
|
||||
|
@ -35,13 +35,12 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
|
||||
stat = wait_for_completion_timeout(&i2c->completion, HZ);
|
||||
val = ddbreadl(dev, i2c->regs + I2C_COMMAND);
|
||||
if (stat == 0) {
|
||||
dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n",
|
||||
dev->nr, i2c->nr, i2c->link);
|
||||
#if 1
|
||||
{
|
||||
u32 istat = ddbreadl(dev, INTERRUPT_STATUS);
|
||||
|
||||
dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n",
|
||||
dev->nr, i2c->nr, i2c->link);
|
||||
dev_err(dev->dev, "DDBridge IRS %08x\n", istat);
|
||||
|
||||
if (i2c->link) {
|
||||
u32 listat =
|
||||
ddbreadl(dev,
|
||||
@ -60,8 +59,6 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd)
|
||||
dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n",
|
||||
val, mon);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return -EIO;
|
||||
}
|
||||
val &= 0x70000;
|
||||
|
@ -1,4 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* ddbridge-i2c.h: Digital Devices bridge i2c driver
|
||||
*
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ddbridge-io.c: Digital Devices bridge I/O functions
|
||||
*
|
||||
|
@ -1,3 +1,4 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
|
||||
#if 0
|
||||
#ifdef DEBUG_GTLW
|
||||
static inline void gtlw(struct ddb_link *link)
|
||||
{
|
||||
u32 count = 0;
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* 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;
|
||||
int res;
|
||||
//struct dtv_frontend_properties *p = &fe->dtv_property_cache;
|
||||
|
||||
stop(fe);
|
||||
|
||||
@ -343,6 +345,7 @@ static int set_parameters(struct dvb_frontend *fe)
|
||||
state->iq_constellation_point_max = 0;
|
||||
|
||||
state->iq_constellation_tap = 0;
|
||||
//printk("bw = %u\n", p->bandwidth_hz);
|
||||
switch (fe->dtv_property_cache.delivery_system) {
|
||||
case SYS_DVBS:
|
||||
case SYS_DVBS2:
|
||||
@ -450,7 +453,7 @@ static void release(struct dvb_frontend *fe)
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static int get_algo(struct dvb_frontend *fe)
|
||||
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
@ -470,12 +473,12 @@ static struct dvb_frontend_ops m4_ops = {
|
||||
SYS_DVBS, SYS_DVBS2, SYS_ISDBS, },
|
||||
.info = {
|
||||
.name = "M4",
|
||||
.frequency_min = 950000, /* DVB-T: 47125000 */
|
||||
.frequency_max = 865000000, /* DVB-C: 862000000 */
|
||||
.frequency_min_hz = 47125000, /* DVB-T: 47125000 */
|
||||
.frequency_max_hz = 2150000000, /* DVB-C: 862000000 */
|
||||
.symbol_rate_min = 100000,
|
||||
.symbol_rate_max = 100000000,
|
||||
.frequency_stepsize = 0,
|
||||
.frequency_tolerance = 0,
|
||||
.frequency_stepsize_hz = 0,
|
||||
.frequency_tolerance_hz = 0,
|
||||
.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_AUTO |
|
||||
|
@ -458,11 +458,9 @@ static pci_ers_result_t ddb_pci_error_detected(struct pci_dev *pdev,
|
||||
{
|
||||
switch (state) {
|
||||
case pci_channel_io_frozen:
|
||||
|
||||
return PCI_ERS_RESULT_CAN_RECOVER;
|
||||
case pci_channel_io_perm_failure:
|
||||
return PCI_ERS_RESULT_DISCONNECT;
|
||||
break;
|
||||
case pci_channel_io_normal:
|
||||
default:
|
||||
break;
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* 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;
|
||||
|
||||
if (len !=4)
|
||||
if (len != 4)
|
||||
return -1;
|
||||
|
||||
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 */
|
||||
|
||||
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)
|
||||
{
|
||||
struct ddb *dev = input->port->dev;
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
/*
|
||||
* ddbridge-mci.c: Digital Devices microcode interface
|
||||
*
|
||||
@ -38,7 +39,7 @@ static int mci_reset(struct mci *state)
|
||||
msleep(300);
|
||||
ddblwritel(link, 0, MCI_CONTROL);
|
||||
|
||||
while(1) {
|
||||
while (1) {
|
||||
status = ddblreadl(link, MCI_CONTROL);
|
||||
if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY)
|
||||
break;
|
||||
@ -46,7 +47,7 @@ static int mci_reset(struct mci *state)
|
||||
break;
|
||||
msleep(50);
|
||||
}
|
||||
if ((status & MCI_CONTROL_READY) == 0 )
|
||||
if ((status & MCI_CONTROL_READY) == 0)
|
||||
return -1;
|
||||
if (link->ids.device == 0x0009 || link->ids.device == 0x000b)
|
||||
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) {
|
||||
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);
|
||||
if (val == 0xffffffff) {
|
||||
printk("Lost PCIe link!\n");
|
||||
dev_err(state->base->link->dev->dev,
|
||||
"Lost PCIe link!\n");
|
||||
return -EIO;
|
||||
} 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)
|
||||
ddblwritel(link, istat, INTERRUPT_ACK);
|
||||
if (link->nr)
|
||||
@ -186,8 +189,7 @@ int ddb_mci_get_snr(struct dvb_frontend *fe)
|
||||
|
||||
p->cnr.len = 1;
|
||||
p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->cnr.stat[0].svalue = (s64) mci->
|
||||
signal_info.dvbs2_signal_info.signal_to_noise * 10;
|
||||
p->cnr.stat[0].svalue = (s64) mci->signal_info.dvbs2_signal_info.signal_to_noise * 10;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -259,7 +261,6 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p)
|
||||
{
|
||||
u32 pls_code =
|
||||
mci->signal_info.dvbs2_signal_info.pls_code;
|
||||
|
||||
p->frequency =
|
||||
mci->signal_info.dvbs2_signal_info.frequency / 1000;
|
||||
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->rolloff =
|
||||
ro_lut[mci->signal_info.
|
||||
dvbs2_signal_info.roll_off & 7];
|
||||
ro_lut[mci->signal_info.dvbs2_signal_info.roll_off & 7];
|
||||
p->pilot = (pls_code & 1) ? PILOT_ON : PILOT_OFF;
|
||||
p->fec_inner = modcod2fec[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.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
p->cnr.stat[0].svalue = (s64) mci->
|
||||
signal_info.dvbs2_signal_info.signal_to_noise * 10;
|
||||
p->cnr.stat[0].svalue = (s64)
|
||||
mci->signal_info.dvbs2_signal_info.signal_to_noise * 10;
|
||||
|
||||
p->strength.len = 1;
|
||||
p->strength.stat[0].scale = FE_SCALE_DECIBEL;
|
||||
|
@ -648,7 +648,6 @@ struct mci_result {
|
||||
struct {
|
||||
u8 Mode; // FFT Mode 1,2,3
|
||||
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
|
||||
} ISDBT_TMCCInfo;
|
||||
|
||||
@ -710,7 +709,7 @@ struct mci_result {
|
||||
|
||||
/* 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_AUX(p) ((p)[3] & 0x0F)
|
||||
#define L1POST_AUX_CONFIG_RFU(p) ((p)[4] & 0xFF)
|
||||
@ -750,8 +749,6 @@ struct mci_base {
|
||||
void *key;
|
||||
struct ddb_link *link;
|
||||
struct completion completion;
|
||||
struct i2c_adapter *i2c;
|
||||
struct mutex i2c_lock;
|
||||
struct mutex tuner_lock;
|
||||
struct mutex mci_lock;
|
||||
int count;
|
||||
@ -788,4 +785,7 @@ int ddb_mci_get_info(struct mci *mci);
|
||||
int ddb_mci_get_strength(struct dvb_frontend *fe);
|
||||
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
|
||||
|
@ -441,11 +441,11 @@ static int ns_start(struct dvbnss *nss)
|
||||
reg |= 0x40;
|
||||
if (nss->params.flags & DVB_NS_IPV6)
|
||||
reg |= 0x80;
|
||||
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
|
||||
STREAM_CONTROL(dns->nr));
|
||||
if (dns->fe != input)
|
||||
ddb_dvb_ns_input_start(dns->fe);
|
||||
ddb_dvb_ns_input_start(input);
|
||||
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
|
||||
STREAM_CONTROL(dns->nr));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -501,7 +501,7 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_algo(struct dvb_frontend *fe)
|
||||
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
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 */
|
||||
.info = {
|
||||
.name = "DVB-S/S2X",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 0,
|
||||
.frequency_tolerance = 0,
|
||||
.frequency_min_hz = 950000000,
|
||||
.frequency_max_hz = 2150000000,
|
||||
.frequency_stepsize_hz = 0,
|
||||
.frequency_tolerance_hz = 0,
|
||||
.symbol_rate_min = 100000,
|
||||
.symbol_rate_max = 100000000,
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
|
@ -60,22 +60,20 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/dma.h>
|
||||
#include <asm/irq.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <linux/dvb/ca.h>
|
||||
#include <linux/socket.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/io.h>
|
||||
|
||||
#include "dvb_netstream.h"
|
||||
#include "dmxdev.h"
|
||||
#include "dvbdev.h"
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb_ringbuffer.h"
|
||||
#include "dvb_ca_en50221.h"
|
||||
#include "dvb_net.h"
|
||||
#include <media/dmxdev.h>
|
||||
#include <media/dvbdev.h>
|
||||
#include <media/dvb_demux.h>
|
||||
#include <media/dvb_frontend.h>
|
||||
#include <media/dvb_ringbuffer.h>
|
||||
#include <media/dvb_ca_en50221.h>
|
||||
#include <media/dvb_net.h>
|
||||
|
||||
#include "tda18271c2dd.h"
|
||||
#include "stv6110x.h"
|
||||
@ -238,7 +236,7 @@ struct ddb_dvb {
|
||||
enum fe_sec_tone_mode tone;
|
||||
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,
|
||||
enum fe_sec_voltage voltage);
|
||||
int (*set_input)(struct dvb_frontend *fe, int input);
|
||||
@ -408,7 +406,7 @@ struct ddb_lnb {
|
||||
};
|
||||
|
||||
struct ddb_irq {
|
||||
void (*handler)(void *);
|
||||
void (*handler)(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);
|
||||
void ddbridge_mod_output_stop(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_nsd_detach(struct ddb *dev);
|
||||
|
@ -38,7 +38,7 @@
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/dvb/ns.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
#include <media/dvbdev.h>
|
||||
|
||||
#define DVBNS_MAXPIDS 32
|
||||
|
||||
|
@ -3,6 +3,32 @@
|
||||
# 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
|
||||
int "maximum number of DVB/ATSC adapters"
|
||||
depends on DVB_CORE
|
||||
@ -19,7 +45,7 @@ config DVB_MAX_ADAPTERS
|
||||
config DVB_DYNAMIC_MINORS
|
||||
bool "Dynamic DVB minor allocation"
|
||||
depends on DVB_CORE
|
||||
default n
|
||||
default y
|
||||
help
|
||||
If you say Y here, the DVB subsystem will use dynamic minor
|
||||
allocation for any device that uses the DVB major number.
|
||||
@ -32,7 +58,6 @@ config DVB_DYNAMIC_MINORS
|
||||
config DVB_DEMUX_SECTION_LOSS_LOG
|
||||
bool "Enable DVB demux section packet loss log"
|
||||
depends on DVB_CORE
|
||||
default n
|
||||
help
|
||||
Enable extra log messages meant to detect packet loss
|
||||
inside the Kernel.
|
||||
@ -41,3 +66,15 @@ config DVB_DEMUX_SECTION_LOSS_LOG
|
||||
be very verbose.
|
||||
|
||||
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.
|
||||
|
@ -3,11 +3,14 @@
|
||||
# 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_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
|
||||
|
||||
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
|
||||
|
@ -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
|
||||
|
||||
obj-$(CONFIG_DVB_CORE) += dvb-core.o
|
||||
|
||||
ccflags-y += -Idrivers/media/dvb-core/
|
||||
|
@ -18,6 +18,7 @@
|
||||
|
||||
#define pr_fmt(fmt) "dmxdev: " fmt
|
||||
|
||||
#include <linux/version.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/slab.h>
|
||||
@ -27,8 +28,10 @@
|
||||
#include <linux/ioctl.h>
|
||||
#include <linux/wait.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/version.h>
|
||||
#include "dmxdev.h"
|
||||
#include <media/dmxdev.h>
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
#include <media/dvb_vb2.h>
|
||||
#endif
|
||||
|
||||
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 dmxdev *dmxdev = dvbdev->priv;
|
||||
struct dmx_frontend *front;
|
||||
bool need_ringbuffer = false;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
@ -139,14 +143,33 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
|
||||
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)) {
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
dmxdev->may_do_mmap = 1;
|
||||
need_ringbuffer = true;
|
||||
#else
|
||||
mutex_unlock(&dmxdev->mutex);
|
||||
return -EOPNOTSUPP;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if ((file->f_flags & O_ACCMODE) == O_RDONLY) {
|
||||
if (need_ringbuffer) {
|
||||
void *mem;
|
||||
|
||||
if (!dvbdev->readers) {
|
||||
@ -159,6 +182,11 @@ static int dvb_dvr_open(struct inode *inode, struct file *file)
|
||||
return -ENOMEM;
|
||||
}
|
||||
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--;
|
||||
}
|
||||
|
||||
@ -196,7 +224,15 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
|
||||
dmxdev->demux->connect_frontend(dmxdev->demux,
|
||||
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++;
|
||||
if (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
|
||||
static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_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;
|
||||
int ret;
|
||||
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
if (!dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx) &&
|
||||
dmxdevfilter->buffer.error) {
|
||||
#else
|
||||
if (dmxdevfilter->buffer.error) {
|
||||
#endif
|
||||
wake_up(&dmxdevfilter->buffer.queue);
|
||||
return 0;
|
||||
}
|
||||
@ -397,12 +439,31 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
}
|
||||
del_timer(&dmxdevfilter->timer);
|
||||
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,
|
||||
buffer1_len);
|
||||
if (ret == buffer1_len) {
|
||||
ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2,
|
||||
buffer2_len);
|
||||
}
|
||||
#endif
|
||||
if (ret < 0)
|
||||
dmxdevfilter->buffer.error = ret;
|
||||
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,
|
||||
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 dvb_ringbuffer *buffer;
|
||||
@ -426,11 +488,28 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
|
||||
|| dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
|
||||
if (dmxdevfilter->params.pes.output == DMX_OUT_TAP ||
|
||||
dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) {
|
||||
buffer = &dmxdevfilter->buffer;
|
||||
else
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
ctx = &dmxdevfilter->vb2_ctx;
|
||||
#endif
|
||||
} else {
|
||||
buffer = &dmxdevfilter->dev->dvr_buffer;
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
ctx = &dmxdevfilter->dev->dvr_vb2_ctx;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
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);
|
||||
@ -438,7 +517,11 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
}
|
||||
ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len);
|
||||
if (ret == buffer1_len)
|
||||
ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len);
|
||||
ret = dvb_dmxdev_buffer_write(buffer,
|
||||
buffer2, buffer2_len);
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
}
|
||||
#endif
|
||||
if (ret < 0)
|
||||
buffer->error = ret;
|
||||
spin_unlock(&dmxdevfilter->dev->lock);
|
||||
@ -585,7 +668,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
|
||||
struct dmxdev_filter *filter,
|
||||
struct dmxdev_feed *feed)
|
||||
{
|
||||
ktime_t timeout;
|
||||
ktime_t timeout = ktime_set(0, 0);
|
||||
struct dmx_pes_filter_params *para = &filter->params.pes;
|
||||
enum dmx_output otype;
|
||||
int ret;
|
||||
@ -593,7 +676,6 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
|
||||
enum dmx_ts_pes ts_pes;
|
||||
struct dmx_ts_feed *tsfeed;
|
||||
|
||||
timeout = ktime_set(0, 0);
|
||||
feed->ts = NULL;
|
||||
otype = para->output;
|
||||
|
||||
@ -777,7 +859,17 @@ static int dvb_demux_open(struct inode *inode, struct file *file)
|
||||
mutex_init(&dmxdevfilter->mutex);
|
||||
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);
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter",
|
||||
file->f_flags & O_NONBLOCK);
|
||||
#endif
|
||||
dmxdevfilter->type = DMXDEV_TYPE_NONE;
|
||||
dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED);
|
||||
#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(&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_reset(dmxdevfilter);
|
||||
@ -1084,8 +1181,56 @@ static int dvb_demux_do_ioctl(struct file *file,
|
||||
mutex_unlock(&dmxdevfilter->mutex);
|
||||
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:
|
||||
ret = -EINVAL;
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
unsigned int mask = 0;
|
||||
|
||||
if ((!dmxdevfilter) || dmxdevfilter->dev->exit)
|
||||
return POLLERR;
|
||||
__poll_t mask = 0;
|
||||
|
||||
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 &&
|
||||
dmxdevfilter->state != DMXDEV_STATE_DONE &&
|
||||
dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT)
|
||||
return 0;
|
||||
|
||||
if (dmxdevfilter->buffer.error)
|
||||
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
|
||||
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
|
||||
|
||||
if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer))
|
||||
mask |= (POLLIN | POLLRDNORM | POLLPRI);
|
||||
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
|
||||
|
||||
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)
|
||||
{
|
||||
struct dmxdev_filter *dmxdevfilter = file->private_data;
|
||||
@ -1146,10 +1331,14 @@ static const struct file_operations dvb_demux_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = dvb_demux_read,
|
||||
.unlocked_ioctl = dvb_demux_ioctl,
|
||||
.compat_ioctl = dvb_demux_ioctl,
|
||||
.open = dvb_demux_open,
|
||||
.release = dvb_demux_release,
|
||||
.poll = dvb_demux_poll,
|
||||
.llseek = default_llseek,
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
.mmap = dvb_demux_mmap,
|
||||
#endif
|
||||
};
|
||||
|
||||
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);
|
||||
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:
|
||||
ret = -EINVAL;
|
||||
ret = -ENOTTY;
|
||||
break;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
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 dmxdev *dmxdev = dvbdev->priv;
|
||||
unsigned int mask = 0;
|
||||
__poll_t mask = 0;
|
||||
|
||||
dprintk("%s\n", __func__);
|
||||
|
||||
if (dmxdev->exit)
|
||||
return POLLERR;
|
||||
|
||||
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)
|
||||
mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR);
|
||||
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR);
|
||||
|
||||
if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer))
|
||||
mask |= (POLLIN | POLLRDNORM | POLLPRI);
|
||||
mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI);
|
||||
} else
|
||||
mask |= (POLLOUT | POLLWRNORM | POLLPRI);
|
||||
mask |= (EPOLLOUT | EPOLLWRNORM | EPOLLPRI);
|
||||
|
||||
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 = {
|
||||
.owner = THIS_MODULE,
|
||||
.read = dvb_dvr_read,
|
||||
@ -1226,6 +1465,9 @@ static const struct file_operations dvb_dvr_fops = {
|
||||
.release = dvb_dvr_release,
|
||||
.poll = dvb_dvr_poll,
|
||||
.llseek = default_llseek,
|
||||
#ifdef CONFIG_DVB_MMAP
|
||||
.mmap = dvb_dvr_mmap,
|
||||
#endif
|
||||
};
|
||||
|
||||
static const struct dvb_device dvbdev_dvr = {
|
||||
@ -1237,6 +1479,7 @@ static const struct dvb_device dvbdev_dvr = {
|
||||
#endif
|
||||
.fops = &dvb_dvr_fops
|
||||
};
|
||||
|
||||
int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter)
|
||||
{
|
||||
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)
|
||||
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)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -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_ */
|
@ -34,8 +34,8 @@
|
||||
#endif
|
||||
#include <linux/kthread.h>
|
||||
|
||||
#include "dvb_ca_en50221.h"
|
||||
#include "dvb_ringbuffer.h"
|
||||
#include <media/dvb_ca_en50221.h>
|
||||
#include <media/dvb_ringbuffer.h>
|
||||
|
||||
static int dvb_ca_en50221_debug;
|
||||
|
||||
|
@ -35,7 +35,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_demux.h"
|
||||
#include <media/dvb_demux.h>
|
||||
|
||||
|
||||
#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0))
|
||||
@ -68,6 +68,17 @@ MODULE_PARM_DESC(dvb_demux_feed_err_pkts,
|
||||
dprintk(x); \
|
||||
} 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
|
||||
******************************************************************************/
|
||||
@ -117,30 +128,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed,
|
||||
{
|
||||
int count = payload(buf);
|
||||
int p;
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
int ccok;
|
||||
u8 cc;
|
||||
#endif
|
||||
|
||||
if (count == 0)
|
||||
return -1;
|
||||
|
||||
p = 188 - count;
|
||||
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
cc = buf[3] & 0x0f;
|
||||
ccok = ((feed->cc + 1) & 0x0f) == cc;
|
||||
feed->cc = cc;
|
||||
if (!ccok)
|
||||
dprintk("missed packet!\n");
|
||||
#endif
|
||||
if (!ccok) {
|
||||
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||
dprintk_sect_loss("missed packet: %d instead of %d!\n",
|
||||
cc, (feed->cc + 1) & 0x0f);
|
||||
}
|
||||
|
||||
if (buf[1] & 0x40) // PUSI ?
|
||||
feed->peslen = 0xfffa;
|
||||
|
||||
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,
|
||||
@ -162,7 +173,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed,
|
||||
return 0;
|
||||
|
||||
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)
|
||||
@ -181,9 +192,11 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed)
|
||||
if (sec->check_crc) {
|
||||
section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
do {
|
||||
if (dvb_dmx_swfilter_sectionfilter(feed, f) < 0)
|
||||
@ -199,9 +212,8 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
|
||||
{
|
||||
struct dmx_section_feed *sec = &feed->feed.sec;
|
||||
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
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.
|
||||
@ -209,15 +221,13 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed)
|
||||
* but just first and last.
|
||||
*/
|
||||
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,
|
||||
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||
dprintk_sect_loss("section ts padding loss: %d/%d\n",
|
||||
n, sec->tsfeedp);
|
||||
dprintk("dvb_demux.c pad data:");
|
||||
for (i = 0; i < n; i++)
|
||||
pr_cont(" %02x", sec->secbuf[i]);
|
||||
pr_cont("\n");
|
||||
dprintk_sect_loss("pad data: %*ph\n", n, sec->secbuf);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
sec->tsfeedp = sec->secbufp = sec->seclen = 0;
|
||||
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.
|
||||
*
|
||||
* 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
|
||||
* 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,
|
||||
const u8 *buf, u8 len)
|
||||
@ -252,11 +262,10 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed,
|
||||
return 0;
|
||||
|
||||
if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) {
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
dprintk("dvb_demux.c section buffer full loss: %d/%d\n",
|
||||
set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||
dprintk_sect_loss("section buffer full loss: %d/%d\n",
|
||||
sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE,
|
||||
DMX_MAX_SECFEED_SIZE);
|
||||
#endif
|
||||
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->crc_val = ~0;
|
||||
/* dump [secbuf .. secbuf+seclen) */
|
||||
if (feed->pusi_seen)
|
||||
if (feed->pusi_seen) {
|
||||
dvb_dmx_swfilter_section_feed(feed);
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
else
|
||||
dprintk("dvb_demux.c pusi not seen, discarding section data\n");
|
||||
#endif
|
||||
} else {
|
||||
set_buf_flags(feed,
|
||||
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED);
|
||||
dprintk_sect_loss("pusi not seen, discarding section data\n");
|
||||
}
|
||||
sec->secbufp += seclen; /* secbufp and secbuf moving together is */
|
||||
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) {
|
||||
#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG
|
||||
dprintk("dvb_demux.c discontinuity detected %d bytes lost\n",
|
||||
count);
|
||||
if (dc_i) {
|
||||
set_buf_flags(feed,
|
||||
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
|
||||
*/
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Discontinuity detected. Reset pusi_seen = 0 to
|
||||
* Discontinuity detected. Reset pusi_seen to
|
||||
* 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);
|
||||
}
|
||||
|
||||
@ -348,17 +370,16 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed,
|
||||
|
||||
dvb_dmx_swfilter_section_copy_dump(feed, before,
|
||||
before_len);
|
||||
/* before start of new section, set pusi_seen = 1 */
|
||||
feed->pusi_seen = 1;
|
||||
/* before start of new section, set pusi_seen */
|
||||
feed->pusi_seen = true;
|
||||
dvb_dmx_swfilter_section_new(feed);
|
||||
dvb_dmx_swfilter_section_copy_dump(feed, after,
|
||||
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 {
|
||||
/* PUSI=0 (is not set), no section boundary */
|
||||
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)
|
||||
dvb_dmx_swfilter_payload(feed, buf);
|
||||
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->demux->write_to_decoder)
|
||||
feed->demux->write_to_decoder(feed, buf, 188);
|
||||
@ -426,6 +449,7 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
||||
1024);
|
||||
speed_timedelta = ktime_ms_delta(cur_time,
|
||||
demux->speed_last_time);
|
||||
if (speed_timedelta)
|
||||
dprintk("TS speed %llu Kbits/sec \n",
|
||||
div64_u64(speed_bytes,
|
||||
speed_timedelta));
|
||||
@ -437,6 +461,11 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
||||
}
|
||||
|
||||
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",
|
||||
pid, buf[1]);
|
||||
/* 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;
|
||||
|
||||
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",
|
||||
pid, demux->cnt_storage[pid],
|
||||
buf[3] & 0xf);
|
||||
@ -473,7 +509,8 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
|
||||
if (feed->pid == pid)
|
||||
dvb_dmx_swfilter_packet_type(feed, buf);
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
@ -792,6 +838,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx,
|
||||
feed->demux = demux;
|
||||
feed->pid = 0xffff;
|
||||
feed->peslen = 0xfffa;
|
||||
feed->buffer_flags = 0;
|
||||
|
||||
(*ts_feed) = &feed->feed.ts;
|
||||
(*ts_feed)->parent = dmx;
|
||||
@ -911,14 +958,14 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed)
|
||||
return;
|
||||
do {
|
||||
sf = &f->filter;
|
||||
doneq = 0;
|
||||
doneq = false;
|
||||
for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) {
|
||||
mode = sf->filter_mode[i];
|
||||
mask = sf->filter_mask[i];
|
||||
f->maskandmode[i] = mask & mode;
|
||||
doneq |= f->maskandnotmode[i] = mask & ~mode;
|
||||
}
|
||||
f->doneq = doneq ? 1 : 0;
|
||||
f->doneq = doneq ? true : false;
|
||||
} 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.secbufp = 0;
|
||||
dvbdmxfeed->feed.sec.seclen = 0;
|
||||
dvbdmxfeed->pusi_seen = false;
|
||||
|
||||
if (!dvbdmx->start_feed) {
|
||||
mutex_unlock(&dvbdmx->mutex);
|
||||
@ -1049,6 +1097,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux,
|
||||
dvbdmxfeed->cb.sec = callback;
|
||||
dvbdmxfeed->demux = dvbdmx;
|
||||
dvbdmxfeed->pid = 0xffff;
|
||||
dvbdmxfeed->buffer_flags = 0;
|
||||
dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base;
|
||||
dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0;
|
||||
dvbdmxfeed->feed.sec.tsfeedp = 0;
|
||||
@ -1220,12 +1269,25 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux)
|
||||
|
||||
dvbdemux->cnt_storage = NULL;
|
||||
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)
|
||||
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) {
|
||||
vfree(dvbdemux->filter);
|
||||
dvbdemux->filter = NULL;
|
||||
|
@ -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
@ -19,7 +19,7 @@
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <asm/bug.h>
|
||||
#include "dvb_math.h"
|
||||
#include <media/dvb_math.h>
|
||||
|
||||
static const unsigned short logtable[256] = {
|
||||
0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7,
|
||||
|
@ -1,3 +1,4 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
/*
|
||||
* dvb_net.c
|
||||
*
|
||||
@ -13,18 +14,6 @@
|
||||
* and Wolfram Stering <wstering@cosy.sbg.ac.at>
|
||||
*
|
||||
* 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.
|
||||
* Bugfixes and robustness improvements.
|
||||
* 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
|
||||
* Christian Praehauser <cpraehaus@cosy.sbg.ac.at>,
|
||||
* Paris Lodron University of Salzburg.
|
||||
@ -69,8 +58,8 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include "dvb_demux.h"
|
||||
#include "dvb_net.h"
|
||||
#include <media/dvb_demux.h>
|
||||
#include <media/dvb_net.h>
|
||||
|
||||
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
|
||||
|
||||
#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)
|
||||
{
|
||||
print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct dvb_net_priv {
|
||||
@ -130,7 +124,7 @@ struct dvb_net_priv {
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
/*
|
||||
* 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.
|
||||
* 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;
|
||||
|
||||
/**
|
||||
/*
|
||||
* 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
|
||||
* 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)
|
||||
return htons(ETH_P_802_3);
|
||||
|
||||
/**
|
||||
/*
|
||||
* Real 802.2 LLC
|
||||
*/
|
||||
return htons(ETH_P_802_2);
|
||||
@ -220,7 +214,8 @@ static int ule_exthdr_padding(struct dvb_net_priv *p)
|
||||
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.
|
||||
* Returns: >= 0: nr. of bytes consumed by next extension header
|
||||
* -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)
|
||||
return l; /* Stop extension header processing and discard SNDU. */
|
||||
total_ext_len += l;
|
||||
#ifdef ULE_DEBUG
|
||||
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,
|
||||
l, total_ext_len);
|
||||
#endif
|
||||
|
||||
} 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 )
|
||||
{
|
||||
p->ule_skb = NULL;
|
||||
@ -309,7 +302,7 @@ static inline void reset_ule( struct dvb_net_priv *p )
|
||||
p->ule_bridged = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
/*
|
||||
* Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of
|
||||
* TS cells of a single PID.
|
||||
*/
|
||||
@ -324,29 +317,21 @@ struct dvb_net_ule_handle {
|
||||
const u8 *ts, *ts_end, *from_where;
|
||||
u8 ts_remain, how_much, new_ts;
|
||||
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)
|
||||
{
|
||||
/* We are about to process a new TS cell. */
|
||||
|
||||
#ifdef ULE_DEBUG
|
||||
if (h->ule_where >= &h->ule_hist[100*TS_SZ])
|
||||
h->ule_where = h->ule_hist;
|
||||
memcpy(h->ule_where, h->ts, TS_SZ);
|
||||
if (h->ule_dump) {
|
||||
hexdump(h->ule_where, TS_SZ);
|
||||
h->ule_dump = 0;
|
||||
#ifdef DVB_ULE_DEBUG
|
||||
if (ule_where >= &ule_hist[100*TS_SZ])
|
||||
ule_where = ule_hist;
|
||||
memcpy(ule_where, h->ts, TS_SZ);
|
||||
if (ule_dump) {
|
||||
hexdump(ule_where, TS_SZ);
|
||||
ule_dump = 0;
|
||||
}
|
||||
h->ule_where += TS_SZ;
|
||||
ule_where += TS_SZ;
|
||||
#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,
|
||||
struct kvec iov[3],
|
||||
u32 ule_crc, u32 expected_crc)
|
||||
{
|
||||
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 ?
|
||||
*(unsigned short *)h->from_where : 0);
|
||||
|
||||
#ifdef ULE_DEBUG
|
||||
#ifdef DVB_ULE_DEBUG
|
||||
hexdump(iov[0].iov_base, iov[0].iov_len);
|
||||
hexdump(iov[1].iov_base, iov[1].iov_len);
|
||||
hexdump(iov[2].iov_base, iov[2].iov_len);
|
||||
|
||||
if (h->ule_where == h->ule_hist) {
|
||||
hexdump(&h->ule_hist[98*TS_SZ], TS_SZ);
|
||||
hexdump(&h->ule_hist[99*TS_SZ], TS_SZ);
|
||||
} else if (h->ule_where == &h->ule_hist[TS_SZ]) {
|
||||
hexdump(&h->ule_hist[99*TS_SZ], TS_SZ);
|
||||
hexdump(h->ule_hist, TS_SZ);
|
||||
if (ule_where == ule_hist) {
|
||||
hexdump(&ule_hist[98*TS_SZ], TS_SZ);
|
||||
hexdump(&ule_hist[99*TS_SZ], TS_SZ);
|
||||
} else if (ule_where == &ule_hist[TS_SZ]) {
|
||||
hexdump(&ule_hist[99*TS_SZ], TS_SZ);
|
||||
hexdump(ule_hist, TS_SZ);
|
||||
} else {
|
||||
hexdump(h->ule_where - TS_SZ - TS_SZ, TS_SZ);
|
||||
hexdump(h->ule_where - TS_SZ, TS_SZ);
|
||||
hexdump(ule_where - TS_SZ - TS_SZ, TS_SZ);
|
||||
hexdump(ule_where - TS_SZ, TS_SZ);
|
||||
}
|
||||
h->ule_dump = 1;
|
||||
ule_dump = 1;
|
||||
#endif
|
||||
|
||||
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 (dvb_net_ule_should_drop(h)) {
|
||||
#ifdef ULE_DEBUG
|
||||
netdev_dbg(h->dev,
|
||||
"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);
|
||||
#endif
|
||||
dev_kfree_skb(h->priv->ule_skb);
|
||||
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 = {
|
||||
.dev = dev,
|
||||
.priv = netdev_priv(dev),
|
||||
.ethh = NULL,
|
||||
.buf = buf,
|
||||
.buf_len = buf_len,
|
||||
.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,
|
||||
.how_much = 0,
|
||||
.new_ts = 1,
|
||||
.ethh = NULL,
|
||||
.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 - 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. */
|
||||
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,
|
||||
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;
|
||||
|
||||
@ -1011,11 +993,11 @@ static void dvb_net_sec(struct net_device *dev,
|
||||
|
||||
static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_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;
|
||||
|
||||
/**
|
||||
/*
|
||||
* we rely on the DVB API definition where exactly one complete
|
||||
* section is delivered in buffer1
|
||||
*/
|
||||
@ -1023,7 +1005,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
|
||||
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);
|
||||
return NETDEV_TX_OK;
|
||||
|
@ -34,7 +34,7 @@
|
||||
#include <linux/uaccess.h>
|
||||
#endif
|
||||
|
||||
#include "dvb_ringbuffer.h"
|
||||
#include <media/dvb_ringbuffer.h>
|
||||
|
||||
#define PKT_READY 0
|
||||
#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(),
|
||||
* 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));
|
||||
#endif
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/device.h>
|
||||
@ -31,7 +32,7 @@
|
||||
#include <linux/cdev.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/version.h>
|
||||
#include "dvbdev.h"
|
||||
#include <media/dvbdev.h>
|
||||
|
||||
#if (LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0))
|
||||
/* Due to enum tuner_pad_index */
|
||||
@ -54,8 +55,19 @@ static LIST_HEAD(dvb_adapter_list);
|
||||
static DEFINE_MUTEX(dvbdev_register_lock);
|
||||
|
||||
static const char * const dnames[] = {
|
||||
"video", "audio", "sec", "frontend", "demux", "dvr", "ca",
|
||||
"net", "osd", "ci", "mod", "ns", "nsd"
|
||||
[DVB_DEVICE_VIDEO] = "video",
|
||||
[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
|
||||
@ -63,7 +75,22 @@ static const char * const dnames[] = {
|
||||
#define DVB_MAX_IDS MAX_DVB_MINORS
|
||||
#else
|
||||
#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)
|
||||
#endif
|
||||
|
||||
@ -319,9 +346,11 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev,
|
||||
if (npads) {
|
||||
dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads),
|
||||
GFP_KERNEL);
|
||||
if (!dvbdev->pads)
|
||||
if (!dvbdev->pads){
|
||||
kfree(dvbdev->entity);
|
||||
return -ENOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case DVB_DEVICE_FRONTEND:
|
||||
@ -420,8 +449,10 @@ static int dvb_register_media_device(struct dvb_device *dvbdev,
|
||||
if (!dvbdev->entity)
|
||||
return 0;
|
||||
|
||||
link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
link = media_create_intf_link(dvbdev->entity,
|
||||
&dvbdev->intf_devnode->intf,
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
#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,
|
||||
const struct dvb_device *template, void *priv, int type,
|
||||
int demux_sink_pads)
|
||||
const struct dvb_device *template, void *priv,
|
||||
enum dvb_device_type type, int demux_sink_pads)
|
||||
{
|
||||
struct dvb_device *dvbdev;
|
||||
struct file_operations *dvbdevfops;
|
||||
@ -454,7 +485,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL);
|
||||
dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL);
|
||||
|
||||
if (!dvbdevfops){
|
||||
kfree (dvbdev);
|
||||
@ -470,7 +501,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev,
|
||||
dvbdev->fops = dvbdevfops;
|
||||
init_waitqueue_head (&dvbdev->wait_queue);
|
||||
|
||||
memcpy(dvbdevfops, template->fops, sizeof(struct file_operations));
|
||||
dvbdevfops->owner = adap->module;
|
||||
|
||||
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);
|
||||
kfree(dvbdevfops);
|
||||
kfree(dvbdev);
|
||||
up_write(&minor_rwsem);
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
return ret;
|
||||
}
|
||||
@ -579,7 +608,8 @@ static int dvb_create_io_intf_links(struct dvb_adapter *adap,
|
||||
if (strncmp(entity->name, name, strlen(name)))
|
||||
continue;
|
||||
link = media_create_intf_link(entity, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -598,8 +628,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
unsigned demux_pad = 0;
|
||||
unsigned dvr_pad = 0;
|
||||
unsigned ntuner = 0, ndemod = 0;
|
||||
u16 source_pad = 0;
|
||||
int ret;
|
||||
int ret, pad_source, pad_sink;
|
||||
static const char *connector_name = "Television";
|
||||
|
||||
if (!mdev)
|
||||
@ -660,17 +689,6 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
return ret;
|
||||
|
||||
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,
|
||||
MEDIA_ENT_F_CONN_RF,
|
||||
conn, 0,
|
||||
@ -679,32 +697,40 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
} 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,
|
||||
MEDIA_ENT_F_CONN_RF,
|
||||
conn, 0,
|
||||
MEDIA_ENT_F_TUNER,
|
||||
tuner, source_pad,
|
||||
tuner, pad_sink,
|
||||
MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
#else
|
||||
pad_sink = TUNER_PAD_RF_INPUT;
|
||||
#endif
|
||||
}
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (ntuner && ndemod) {
|
||||
|
||||
#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;
|
||||
/* NOTE: first found tuner source pad presumed correct */
|
||||
pad_source = media_get_pad_index(tuner, false,
|
||||
PAD_SIGNAL_ANALOG);
|
||||
if (pad_source < 0)
|
||||
return -EINVAL;
|
||||
#else
|
||||
source_pad = TUNER_PAD_OUTPUT;
|
||||
pad_source = TUNER_PAD_OUTPUT;
|
||||
#endif
|
||||
|
||||
ret = media_create_pad_links(mdev,
|
||||
MEDIA_ENT_F_TUNER,
|
||||
tuner, source_pad,
|
||||
tuner, pad_source,
|
||||
MEDIA_ENT_F_DTV_DEMOD,
|
||||
demod, 0, MEDIA_LNK_FL_ENABLED,
|
||||
false);
|
||||
@ -757,14 +783,16 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
media_device_for_each_intf(intf, mdev) {
|
||||
if (intf->type == MEDIA_INTF_T_DVB_CA && ca) {
|
||||
link = media_create_intf_link(ca, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) {
|
||||
link = media_create_intf_link(tuner, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -776,7 +804,8 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
*/
|
||||
if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) {
|
||||
link = media_create_intf_link(demux, intf,
|
||||
MEDIA_LNK_FL_ENABLED);
|
||||
MEDIA_LNK_FL_ENABLED |
|
||||
MEDIA_LNK_FL_IMMUTABLE);
|
||||
if (!link)
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -862,6 +891,10 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name,
|
||||
adap->mfe_dvbdev = NULL;
|
||||
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);
|
||||
|
||||
mutex_unlock(&dvbdev_register_lock);
|
||||
@ -882,7 +915,7 @@ EXPORT_SYMBOL(dvb_unregister_adapter);
|
||||
|
||||
/* if the miracle happens and "generic_usercopy()" is included into
|
||||
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
|
||||
cards (ie. the budget dvb-cards don't need the v4l module...) */
|
||||
int dvb_usercopy(struct file *file,
|
||||
@ -946,6 +979,57 @@ out:
|
||||
}
|
||||
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)
|
||||
{
|
||||
struct dvb_device *dvbdev = dev_get_drvdata(dev);
|
||||
|
@ -16,7 +16,6 @@ EXTRA_CFLAGS += -DCONFIG_DVB_LNBH25
|
||||
EXTRA_CFLAGS += -DCONFIG_DVB_MXL5XX
|
||||
EXTRA_CFLAGS += -DCONFIG_DVB_CXD2099
|
||||
EXTRA_CFLAGS += -DDBVALS
|
||||
NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core
|
||||
|
||||
drxk-objs := drxk_hard.o
|
||||
obj-$(CONFIG_DVB_DRXK) += drxk.o
|
||||
|
@ -25,7 +25,7 @@
|
||||
#ifndef _CXD2099_H_
|
||||
#define _CXD2099_H_
|
||||
|
||||
#include <dvb_ca_en50221.h>
|
||||
#include <media/dvb_ca_en50221.h>
|
||||
|
||||
struct cxd2099_cfg {
|
||||
u32 bitrate;
|
||||
|
@ -35,8 +35,8 @@
|
||||
#include <linux/mutex.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include "dvb_math.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
#include <media/dvb_math.h>
|
||||
#include "cxd2843.h"
|
||||
|
||||
#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,
|
||||
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;
|
||||
memcpy(data + 1, regd, len);
|
||||
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;
|
||||
}
|
||||
|
||||
static int get_algo(struct dvb_frontend *fe)
|
||||
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
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 },
|
||||
.info = {
|
||||
.name = "CXD2854 DVB-C/C2 DVB-T/T2 ISDB-T",
|
||||
.frequency_stepsize = 166667, /* DVB-T only */
|
||||
.frequency_min = 47000000, /* DVB-T: 47125000 */
|
||||
.frequency_max = 865000000, /* DVB-C: 862000000 */
|
||||
.frequency_stepsize_hz = 166667, /* DVB-T only */
|
||||
.frequency_min_hz = 47000000, /* DVB-T: 47125000 */
|
||||
.frequency_max_hz = 865000000, /* DVB-C: 862000000 */
|
||||
.symbol_rate_min = 870000,
|
||||
.symbol_rate_max = 11700000,
|
||||
.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 },
|
||||
.info = {
|
||||
.name = "CXD2843 DVB-C/C2 DVB-T/T2",
|
||||
.frequency_stepsize = 166667, /* DVB-T only */
|
||||
.frequency_min = 47000000, /* DVB-T: 47125000 */
|
||||
.frequency_max = 865000000, /* DVB-C: 862000000 */
|
||||
.frequency_stepsize_hz = 166667, /* DVB-T only */
|
||||
.frequency_min_hz = 47000000, /* DVB-T: 47125000 */
|
||||
.frequency_max_hz = 865000000, /* DVB-C: 862000000 */
|
||||
.symbol_rate_min = 870000,
|
||||
.symbol_rate_max = 11700000,
|
||||
.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 },
|
||||
.info = {
|
||||
.name = "CXD2837 DVB-C DVB-T/T2",
|
||||
.frequency_stepsize = 166667, /* DVB-T only */
|
||||
.frequency_min = 47000000, /* DVB-T: 47125000 */
|
||||
.frequency_max = 865000000, /* DVB-C: 862000000 */
|
||||
.frequency_stepsize_hz = 166667, /* DVB-T only */
|
||||
.frequency_min_hz = 47000000, /* DVB-T: 47125000 */
|
||||
.frequency_max_hz = 865000000, /* DVB-C: 862000000 */
|
||||
.symbol_rate_min = 870000,
|
||||
.symbol_rate_max = 11700000,
|
||||
.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 },
|
||||
.info = {
|
||||
.name = "CXD2838 ISDB-T",
|
||||
.frequency_stepsize = 166667,
|
||||
.frequency_min = 47000000,
|
||||
.frequency_max = 865000000,
|
||||
.frequency_stepsize_hz = 166667,
|
||||
.frequency_min_hz = 47000000,
|
||||
.frequency_max_hz = 865000000,
|
||||
.symbol_rate_min = 870000,
|
||||
.symbol_rate_max = 11700000,
|
||||
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
#include "drxk.h"
|
||||
#include "drxk_hard.h"
|
||||
|
||||
@ -2804,10 +2804,12 @@ static int DVBTScCommand(struct drxk_state *state,
|
||||
case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM:
|
||||
status = Write16_0(state, OFDM_SC_RA_RAM_PARAM1__A, param1);
|
||||
/* All commands using 1 parameters */
|
||||
/* fall through */
|
||||
case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING:
|
||||
case OFDM_SC_RA_RAM_CMD_USER_IO:
|
||||
status = Write16_0(state, OFDM_SC_RA_RAM_PARAM0__A, param0);
|
||||
/* All commands using 0 parameters */
|
||||
/* fall through */
|
||||
case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM:
|
||||
case OFDM_SC_RA_RAM_CMD_NULL:
|
||||
/* Write command */
|
||||
@ -3215,7 +3217,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
|
||||
case TRANSMISSION_MODE_AUTO:
|
||||
default:
|
||||
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:
|
||||
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K;
|
||||
break;
|
||||
@ -3233,7 +3236,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
|
||||
default:
|
||||
case GUARD_INTERVAL_AUTO:
|
||||
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:
|
||||
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4;
|
||||
break;
|
||||
@ -3258,9 +3262,10 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
|
||||
case HIERARCHY_NONE:
|
||||
default:
|
||||
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;
|
||||
//break;
|
||||
/* fall through */
|
||||
case HIERARCHY_1:
|
||||
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1;
|
||||
break;
|
||||
@ -3282,7 +3287,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
|
||||
case QAM_AUTO:
|
||||
default:
|
||||
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:
|
||||
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64;
|
||||
break;
|
||||
@ -3325,7 +3331,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF
|
||||
case FEC_AUTO:
|
||||
default:
|
||||
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 :
|
||||
transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3;
|
||||
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 = {
|
||||
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBC_ANNEX_C },
|
||||
.info = {
|
||||
.name = "DRXK DVB-C",
|
||||
.type = FE_QAM,
|
||||
.frequency_stepsize = 62500,
|
||||
.frequency_min = 47000000,
|
||||
.frequency_max = 862000000,
|
||||
.frequency_stepsize_hz = 62500,
|
||||
.frequency_min_hz = 47000000,
|
||||
.frequency_max_hz = 862000000,
|
||||
.symbol_rate_min = 870000,
|
||||
.symbol_rate_max = 11700000,
|
||||
.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 = {
|
||||
.delsys = { SYS_DVBT },
|
||||
.info = {
|
||||
.name = "DRXK DVB-T",
|
||||
.type = FE_OFDM,
|
||||
.frequency_min = 47125000,
|
||||
.frequency_max = 865000000,
|
||||
.frequency_stepsize = 166667,
|
||||
.frequency_tolerance = 0,
|
||||
.frequency_min_hz = 47125000,
|
||||
.frequency_max_hz = 865000000,
|
||||
.frequency_stepsize_hz = 166667,
|
||||
.frequency_tolerance_hz = 0,
|
||||
.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_AUTO |
|
||||
|
@ -30,7 +30,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
#include "lnbh25.h"
|
||||
|
||||
struct lnbh25 {
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
#include "lnbp21.h"
|
||||
#include "lnbh24.h"
|
||||
|
||||
|
@ -41,7 +41,7 @@
|
||||
#include <asm/div64.h>
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
#include "mxl5xx.h"
|
||||
#include "mxl5xx_regs.h"
|
||||
#include "mxl5xx_defs.h"
|
||||
@ -392,7 +392,7 @@ static void release(struct dvb_frontend *fe)
|
||||
kfree(state);
|
||||
}
|
||||
|
||||
static int get_algo(struct dvb_frontend *fe)
|
||||
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
@ -786,6 +786,7 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* fallthrough */
|
||||
case SYS_DVBS:
|
||||
switch ((MXL_HYDRA_MODULATION_E)
|
||||
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 */
|
||||
.info = {
|
||||
.name = "MXL5XX",
|
||||
.frequency_min = 300000,
|
||||
.frequency_max = 2350000,
|
||||
.frequency_stepsize = 0,
|
||||
.frequency_tolerance = 0,
|
||||
.frequency_min_hz = 300000000,
|
||||
.frequency_max_hz = 2350000000,
|
||||
.frequency_stepsize_hz = 0,
|
||||
.frequency_tolerance_hz = 0,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
#include "stv0367dd.h"
|
||||
#include "stv0367dd_regs.h"
|
||||
|
||||
@ -2074,9 +2074,9 @@ static struct dvb_frontend_ops common_ops = {
|
||||
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT },
|
||||
.info = {
|
||||
.name = "STV0367 DVB-C DVB-T",
|
||||
.frequency_stepsize = 166667, /* DVB-T only */
|
||||
.frequency_min = 47000000, /* DVB-T: 47125000 */
|
||||
.frequency_max = 865000000, /* DVB-C: 862000000 */
|
||||
.frequency_stepsize_hz = 166667, /* DVB-T only */
|
||||
.frequency_min_hz = 47000000, /* DVB-T: 47125000 */
|
||||
.frequency_max_hz = 865000000, /* DVB-C: 862000000 */
|
||||
.symbol_rate_min = 870000,
|
||||
.symbol_rate_max = 11700000,
|
||||
.caps = /* DVB-C */
|
||||
|
@ -28,7 +28,7 @@
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
#include "stv6110x.h" /* for demodulator internal modes */
|
||||
|
||||
@ -5142,10 +5142,10 @@ static struct dvb_frontend_ops stv090x_ops = {
|
||||
#ifdef USE_API3
|
||||
.type = FE_QPSK,
|
||||
#endif
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 0,
|
||||
.frequency_tolerance = 0,
|
||||
.frequency_min_hz = 950000000,
|
||||
.frequency_max_hz = 2150000000,
|
||||
.frequency_stepsize_hz = 0,
|
||||
.frequency_tolerance_hz = 0,
|
||||
.symbol_rate_min = 1000000,
|
||||
.symbol_rate_max = 45000000,
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
|
@ -22,7 +22,7 @@
|
||||
#ifndef __STV090x_PRIV_H
|
||||
#define __STV090x_PRIV_H
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
#define FE_ERROR 0
|
||||
#define FE_NOTICE 1
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
#include "stv0910.h"
|
||||
#include "stv0910_regs.h"
|
||||
|
||||
@ -1581,7 +1581,7 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int get_algo(struct dvb_frontend *fe)
|
||||
static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
|
||||
{
|
||||
return DVBFE_ALGO_HW;
|
||||
}
|
||||
@ -1801,10 +1801,10 @@ static struct dvb_frontend_ops stv0910_ops = {
|
||||
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
|
||||
.info = {
|
||||
.name = "STV0910",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_stepsize = 0,
|
||||
.frequency_tolerance = 0,
|
||||
.frequency_min_hz = 950000000,
|
||||
.frequency_max_hz = 2150000000,
|
||||
.frequency_stepsize_hz = 0,
|
||||
.frequency_tolerance_hz = 0,
|
||||
.symbol_rate_min = 100000,
|
||||
.symbol_rate_max = 70000000,
|
||||
.caps = FE_CAN_INVERSION_AUTO |
|
||||
|
@ -26,7 +26,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
#include "stv6110x_reg.h"
|
||||
#include "stv6110x.h"
|
||||
@ -346,9 +346,9 @@ static void stv6110x_release(struct dvb_frontend *fe)
|
||||
static const struct dvb_tuner_ops stv6110x_ops = {
|
||||
.info = {
|
||||
.name = "STV6110(A) Silicon Tuner",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_step = 0,
|
||||
.frequency_min_hz = 950000000,
|
||||
.frequency_max_hz = 2150000000,
|
||||
.frequency_step_hz = 0,
|
||||
},
|
||||
.release = stv6110x_release
|
||||
};
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
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 = {
|
||||
.info = {
|
||||
.name = "STV6111",
|
||||
.frequency_min = 950000,
|
||||
.frequency_max = 2150000,
|
||||
.frequency_step = 0
|
||||
.frequency_min_hz = 950000000,
|
||||
.frequency_max_hz = 2150000000,
|
||||
.frequency_step_hz = 0
|
||||
},
|
||||
.init = init,
|
||||
.sleep = sleep,
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
#ifndef CHK_ERROR
|
||||
#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 = {
|
||||
.info = {
|
||||
.name = "NXP TDA18212",
|
||||
.frequency_min = 47125000,
|
||||
.frequency_max = 865000000,
|
||||
.frequency_step = 62500
|
||||
.frequency_min_hz = 47125000,
|
||||
.frequency_max_hz = 865000000,
|
||||
.frequency_step_hz = 62500
|
||||
},
|
||||
.init = init,
|
||||
.sleep = sleep,
|
||||
|
@ -32,7 +32,7 @@
|
||||
#include <linux/version.h>
|
||||
#include <asm/div64.h>
|
||||
|
||||
#include "dvb_frontend.h"
|
||||
#include <media/dvb_frontend.h>
|
||||
|
||||
struct SStandardParam {
|
||||
s32 m_IFFrequency;
|
||||
@ -1183,6 +1183,7 @@ static int set_params(struct dvb_frontend *fe,
|
||||
|
||||
switch (delsys) {
|
||||
case SYS_DVBT:
|
||||
/* fallthrough */
|
||||
case SYS_DVBT2:
|
||||
switch (bw) {
|
||||
case 6000000:
|
||||
@ -1197,7 +1198,9 @@ static int set_params(struct dvb_frontend *fe,
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case SYS_DVBC_ANNEX_A:
|
||||
/* fallthrough */
|
||||
case SYS_DVBC_ANNEX_C:
|
||||
if (bw <= 6000000)
|
||||
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 = {
|
||||
.info = {
|
||||
.name = "NXP TDA18271C2D",
|
||||
.frequency_min = 47125000,
|
||||
.frequency_max = 865000000,
|
||||
.frequency_step = 62500
|
||||
.frequency_min_hz = 47125000,
|
||||
.frequency_max_hz = 865000000,
|
||||
.frequency_step_hz = 62500
|
||||
},
|
||||
.init = init,
|
||||
.sleep = sleep,
|
||||
|
@ -117,7 +117,7 @@ struct dmx_ts_feed {
|
||||
* specified by @filter_value that will be used on the filter
|
||||
* match logic.
|
||||
* @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.
|
||||
*
|
||||
*
|
||||
@ -130,8 +130,9 @@ struct dmx_section_filter {
|
||||
u8 filter_value[DMX_MAX_FILTER_SIZE];
|
||||
u8 filter_mask[DMX_MAX_FILTER_SIZE];
|
||||
u8 filter_mode[DMX_MAX_FILTER_SIZE];
|
||||
struct dmx_section_feed *parent; /* Back-pointer */
|
||||
void *priv; /* Pointer to private data of the API client */
|
||||
struct dmx_section_feed *parent;
|
||||
|
||||
void *priv;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -193,6 +194,10 @@ struct dmx_section_feed {
|
||||
* @buffer2: Pointer to the tail of the filtered TS packets, or NULL.
|
||||
* @buffer2_length: Length of the TS data in buffer2.
|
||||
* @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,
|
||||
* 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,
|
||||
const u8 *buffer2,
|
||||
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
|
||||
@ -261,6 +267,10 @@ typedef int (*dmx_ts_cb)(const u8 *buffer1,
|
||||
* including headers and CRC.
|
||||
* @source: Indicates which section 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,
|
||||
* 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,
|
||||
const u8 *buffer2,
|
||||
size_t buffer2_len,
|
||||
struct dmx_section_filter *source);
|
||||
struct dmx_section_filter *source,
|
||||
u32 *buffer_flags);
|
||||
|
||||
/*
|
||||
* DVB Front-End
|
220
include/linux/media/dmxdev.h
Normal file
220
include/linux/media/dmxdev.h
Normal 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_ */
|
@ -20,7 +20,7 @@
|
||||
#include <linux/list.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_CHANGED 2
|
354
include/linux/media/dvb_demux.h
Normal file
354
include/linux/media/dvb_demux.h
Normal 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_ */
|
@ -46,10 +46,11 @@
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <linux/dvb/frontend.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
#include <media/dvbdev.h>
|
||||
|
||||
/*
|
||||
* Maximum number of Delivery systems per frontend. It
|
||||
@ -57,6 +58,10 @@
|
||||
*/
|
||||
#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
|
||||
*
|
||||
@ -78,22 +83,19 @@ struct dvb_frontend;
|
||||
* struct dvb_tuner_info - Frontend name and min/max ranges/bandwidths
|
||||
*
|
||||
* @name: name of the Frontend
|
||||
* @frequency_min: minimal frequency supported
|
||||
* @frequency_max: maximum frequency supported
|
||||
* @frequency_step: frequency step
|
||||
* @frequency_min_hz: minimal frequency supported in Hz
|
||||
* @frequency_max_hz: maximum frequency supported in Hz
|
||||
* @frequency_step_hz: frequency step in Hz
|
||||
* @bandwidth_min: minimal frontend bandwidth supported
|
||||
* @bandwidth_max: maximum frontend bandwidth supported
|
||||
* @bandwidth_step: frontend bandwidth step
|
||||
*
|
||||
* NOTE: frequency parameters are in Hz, for terrestrial/cable or kHz for
|
||||
* satellite.
|
||||
*/
|
||||
struct dvb_tuner_info {
|
||||
char name[128];
|
||||
|
||||
u32 frequency_min;
|
||||
u32 frequency_max;
|
||||
u32 frequency_step;
|
||||
u32 frequency_min_hz;
|
||||
u32 frequency_max_hz;
|
||||
u32 frequency_step_hz;
|
||||
|
||||
u32 bandwidth_min;
|
||||
u32 bandwidth_max;
|
||||
@ -145,10 +147,10 @@ struct analog_parameters {
|
||||
* These devices have AUTO recovery capabilities from LOCK failure
|
||||
*/
|
||||
enum dvbfe_algo {
|
||||
DVBFE_ALGO_HW = (1 << 0),
|
||||
DVBFE_ALGO_SW = (1 << 1),
|
||||
DVBFE_ALGO_CUSTOM = (1 << 2),
|
||||
DVBFE_ALGO_RECOVERY = (1 << 31)
|
||||
DVBFE_ALGO_HW = BIT(0),
|
||||
DVBFE_ALGO_SW = BIT(1),
|
||||
DVBFE_ALGO_CUSTOM = BIT(2),
|
||||
DVBFE_ALGO_RECOVERY = BIT(31),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -164,7 +166,7 @@ enum dvbfe_algo {
|
||||
* The frontend search for a signal failed
|
||||
*
|
||||
* @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
|
||||
*
|
||||
* @DVBFE_ALGO_SEARCH_ERROR:
|
||||
@ -174,19 +176,19 @@ enum dvbfe_algo {
|
||||
* The frontend search algorithm was requested to search again
|
||||
*/
|
||||
enum dvbfe_search {
|
||||
DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0),
|
||||
DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1),
|
||||
DVBFE_ALGO_SEARCH_FAILED = (1 << 2),
|
||||
DVBFE_ALGO_SEARCH_INVALID = (1 << 3),
|
||||
DVBFE_ALGO_SEARCH_AGAIN = (1 << 4),
|
||||
DVBFE_ALGO_SEARCH_ERROR = (1 << 31),
|
||||
DVBFE_ALGO_SEARCH_SUCCESS = BIT(0),
|
||||
DVBFE_ALGO_SEARCH_ASLEEP = BIT(1),
|
||||
DVBFE_ALGO_SEARCH_FAILED = BIT(2),
|
||||
DVBFE_ALGO_SEARCH_INVALID = BIT(3),
|
||||
DVBFE_ALGO_SEARCH_AGAIN = BIT(4),
|
||||
DVBFE_ALGO_SEARCH_ERROR = BIT(31),
|
||||
};
|
||||
|
||||
/**
|
||||
* struct dvb_tuner_ops - Tuner information and callbacks
|
||||
*
|
||||
* @info: embedded struct dvb_tuner_info with tuner properties
|
||||
* @release: callback function called when frontend is dettached.
|
||||
* @info: embedded &struct dvb_tuner_info with tuner properties
|
||||
* @release: callback function called when frontend is detached.
|
||||
* drivers should free any allocated memory.
|
||||
* @init: callback function used to initialize the tuner device.
|
||||
* @sleep: callback function used to put the tuner to sleep.
|
||||
@ -196,25 +198,25 @@ enum dvbfe_search {
|
||||
* resuming from suspend.
|
||||
* @set_params: callback function used to inform the tuner to tune
|
||||
* into a digital TV channel. The properties to be used
|
||||
* are stored at @dvb_frontend.dtv_property_cache;. The
|
||||
* tuner demod can change the parameters to reflect the
|
||||
* changes needed for the channel to be tuned, and
|
||||
* are stored at &struct dvb_frontend.dtv_property_cache.
|
||||
* The tuner demod can change the parameters to reflect
|
||||
* the changes needed for the channel to be tuned, and
|
||||
* update statistics. This is the recommended way to set
|
||||
* the tuner parameters and should be used on newer
|
||||
* drivers.
|
||||
* @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.
|
||||
* @set_config: callback function used to send some tuner-specific
|
||||
* parameters.
|
||||
* @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,
|
||||
* should return 0.
|
||||
* @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,
|
||||
* 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
|
||||
* drift due to AFC.
|
||||
* @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_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.
|
||||
*
|
||||
*/
|
||||
@ -236,7 +238,7 @@ struct dvb_tuner_ops {
|
||||
int (*suspend)(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_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
|
||||
* demodulator parameters needed to decode an analog or
|
||||
* 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.
|
||||
* @get_afc: Used only by analog TV core. Reports the frequency
|
||||
* drift due to AFC.
|
||||
* @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.
|
||||
* @release: callback function called when frontend is dettached.
|
||||
* @release: callback function called when frontend is detached.
|
||||
* drivers should free any allocated memory.
|
||||
* @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C
|
||||
* mux support instead.
|
||||
@ -321,20 +323,48 @@ struct analog_demod_ops {
|
||||
|
||||
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
|
||||
* 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
|
||||
* @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.
|
||||
* @release: callback function called when frontend is ready to be
|
||||
* freed.
|
||||
* 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
|
||||
* allocated by the driver.
|
||||
* @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.
|
||||
* Should not be used on new drivers.
|
||||
* @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.
|
||||
* @set_frontend: callback function used to inform the demod to set the
|
||||
* parameters for demodulating a digital TV channel.
|
||||
* The properties to be used are stored at
|
||||
* @dvb_frontend.dtv_property_cache;. The demod can change
|
||||
* The properties to be used are stored at &struct
|
||||
* dvb_frontend.dtv_property_cache. The demod can change
|
||||
* the parameters to reflect the changes needed for the
|
||||
* channel to be decoded, and update statistics.
|
||||
* @get_tune_settings: callback function
|
||||
* @get_frontend: callback function used to inform the parameters
|
||||
* 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
|
||||
* an error code if the statistics are not available
|
||||
* because the demog is not locked.
|
||||
* @read_status: returns the locking status of the frontend.
|
||||
* @read_ber: legacy callback function to return the bit error rate.
|
||||
* 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.
|
||||
* @read_signal_strength: legacy callback function to return the signal
|
||||
* 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
|
||||
* compatibility is wanted.
|
||||
* @read_snr: legacy callback function to return the Signal/Noise
|
||||
* 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
|
||||
* compatibility is wanted.
|
||||
* @read_ucblocks: legacy callback function to return the Uncorrected Error
|
||||
* 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
|
||||
* compatibility is wanted.
|
||||
* @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
|
||||
* 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
|
||||
* FE_DISEQC_RECV_SLAVE_REPLY ioctl (only Satellite)
|
||||
* FE_DISEQC_RECV_SLAVE_REPLY() ioctl (only Satellite)
|
||||
* @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
|
||||
* FE_SET_TONE ioctl (only Satellite).
|
||||
* FE_SET_TONE() ioctl (only Satellite).
|
||||
* @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
|
||||
* 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
|
||||
* 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
|
||||
* core emulation fails to provide proper support (e.g.
|
||||
* 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.
|
||||
* @set_lna: callback function to power on/off/auto the LNA.
|
||||
* @search: callback function used on some custom algo search algos.
|
||||
* @tuner_ops: pointer to struct dvb_tuner_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.
|
||||
* @tuner_ops: pointer to &struct dvb_tuner_ops
|
||||
* @analog_ops: pointer to &struct analog_demod_ops
|
||||
*/
|
||||
struct dvb_frontend_ops {
|
||||
|
||||
struct dvb_frontend_info info;
|
||||
struct dvb_frontend_internal_info info;
|
||||
|
||||
u8 delsys[MAX_DELSYS];
|
||||
|
||||
@ -473,9 +499,6 @@ struct dvb_frontend_ops {
|
||||
struct dvb_tuner_ops tuner_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];
|
||||
};
|
||||
|
||||
@ -642,11 +665,6 @@ struct dtv_frontend_properties {
|
||||
struct dtv_fe_stats post_bit_count;
|
||||
struct dtv_fe_stats block_error;
|
||||
struct dtv_fe_stats block_count;
|
||||
|
||||
/* private: */
|
||||
/* Cache State */
|
||||
u32 state;
|
||||
|
||||
};
|
||||
|
||||
#define DVB_FE_NO_EXIT 0
|
||||
@ -657,16 +675,16 @@ struct dtv_frontend_properties {
|
||||
/**
|
||||
* 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
|
||||
* @ops: embedded struct dvb_frontend_ops
|
||||
* @dvb: pointer to struct dvb_adapter
|
||||
* @ops: embedded &struct dvb_frontend_ops
|
||||
* @dvb: pointer to &struct dvb_adapter
|
||||
* @demodulator_priv: demod private data
|
||||
* @tuner_priv: tuner private data
|
||||
* @frontend_priv: frontend private data
|
||||
* @sec_priv: SEC 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
|
||||
* either the tuner or the demodulator.
|
||||
* @id: Frontend ID
|
||||
@ -695,8 +713,8 @@ struct dvb_frontend {
|
||||
/**
|
||||
* dvb_register_frontend() - Registers a DVB frontend at the adapter
|
||||
*
|
||||
* @dvb: pointer to the dvb adapter
|
||||
* @fe: pointer to the frontend struct
|
||||
* @dvb: pointer to &struct dvb_adapter
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* Allocate and initialize the private data needed by the frontend core to
|
||||
* 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
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* Stops the frontend kthread, calls dvb_unregister_device() and frees the
|
||||
* 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
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* This function should be called after dvb_unregister_frontend(). It
|
||||
* calls the SEC, tuner and demod release functions:
|
||||
* &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_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
|
||||
* 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
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @fe: pointer to the frontend struct
|
||||
* @fe: pointer to &struct dvb_frontend
|
||||
*
|
||||
* Calls &dvb_frontend_ops.init\(\) and &dvb_frontend_ops.tuner_ops.init\(\),
|
||||
* 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
|
||||
* add_usec parameter
|
||||
*
|
||||
* @waketime: pointer to a struct ktime_t
|
||||
* @waketime: pointer to &struct ktime_t
|
||||
* @add_usec: time to sleep, in microseconds
|
||||
*
|
||||
* 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
|
||||
* satellite subsystem.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* NOTE: it should not be used at the drivers, as the emulation for the
|
@ -24,12 +24,28 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#include "dvbdev.h"
|
||||
#include <media/dvbdev.h>
|
||||
|
||||
#define DVB_NET_DEVICES_MAX 10
|
||||
|
||||
#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_device *dvbdev;
|
||||
struct net_device *device[DVB_NET_DEVICES_MAX];
|
||||
@ -39,8 +55,22 @@ struct dvb_net {
|
||||
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
|
||||
|
280
include/linux/media/dvb_vb2.h
Normal file
280
include/linux/media/dvb_vb2.h
Normal 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 */
|
@ -35,19 +35,42 @@
|
||||
|
||||
#define DVB_UNSET (-1)
|
||||
|
||||
#define DVB_DEVICE_VIDEO 0
|
||||
#define DVB_DEVICE_AUDIO 1
|
||||
#define DVB_DEVICE_SEC 2
|
||||
#define DVB_DEVICE_FRONTEND 3
|
||||
#define DVB_DEVICE_DEMUX 4
|
||||
#define DVB_DEVICE_DVR 5
|
||||
#define DVB_DEVICE_CA 6
|
||||
#define DVB_DEVICE_NET 7
|
||||
#define DVB_DEVICE_OSD 8
|
||||
#define DVB_DEVICE_CI 9
|
||||
#define DVB_DEVICE_MOD 10
|
||||
#define DVB_DEVICE_NS 11
|
||||
#define DVB_DEVICE_NSD 12
|
||||
/* List of DVB device types */
|
||||
|
||||
/**
|
||||
* enum dvb_device_type - type of the Digital TV device
|
||||
*
|
||||
* @DVB_DEVICE_SEC: Digital TV standalone Common Interface (CI)
|
||||
* @DVB_DEVICE_FRONTEND: Digital TV frontend.
|
||||
* @DVB_DEVICE_DEMUX: Digital TV demux.
|
||||
* @DVB_DEVICE_DVR: Digital TV digital video record (DVR).
|
||||
* @DVB_DEVICE_CA: Digital TV Conditional Access (CA).
|
||||
* @DVB_DEVICE_NET: Digital TV network.
|
||||
*
|
||||
* @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) \
|
||||
static short adapter_nr[] = \
|
||||
@ -68,11 +91,12 @@ struct dvb_frontend;
|
||||
* @priv: private data
|
||||
* @device: pointer to struct device
|
||||
* @module: pointer to struct module
|
||||
* @mfe_shared: mfe shared: indicates mutually exclusive frontends
|
||||
* Thie usage of this flag is currently deprecated
|
||||
* @mfe_shared: indicates mutually exclusive frontends.
|
||||
* Use of this flag is currently deprecated.
|
||||
* @mfe_dvbdev: Frontend device in use, in the case of MFE
|
||||
* @mfe_lock: Lock to prevent using the other frontends when MFE is
|
||||
* used.
|
||||
* @mdev_lock: Protect access to the mdev pointer.
|
||||
* @mdev: pointer to struct media_device, used when the media
|
||||
* controller is used.
|
||||
* @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 */
|
||||
|
||||
#if defined(CONFIG_MEDIA_CONTROLLER_DVB)
|
||||
struct mutex mdev_lock;
|
||||
struct media_device *mdev;
|
||||
struct media_entity *conn;
|
||||
struct media_pad *conn_pads;
|
||||
@ -108,8 +133,7 @@ struct dvb_adapter {
|
||||
* @list_head: List head with all DVB devices
|
||||
* @fops: pointer to struct file_operations
|
||||
* @adapter: pointer to the adapter that holds this device node
|
||||
* @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND,
|
||||
* DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET
|
||||
* @type: type of the device, as defined by &enum dvb_device_type.
|
||||
* @minor: devnode minor number. Major number is always DVB_MAJOR.
|
||||
* @id: device ID number, inside the adapter
|
||||
* @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;
|
||||
const struct file_operations *fops;
|
||||
struct dvb_adapter *adapter;
|
||||
int type;
|
||||
enum dvb_device_type type;
|
||||
int minor;
|
||||
u32 id;
|
||||
|
||||
@ -198,9 +222,7 @@ int dvb_unregister_adapter(struct dvb_adapter *adap);
|
||||
* stored
|
||||
* @template: Template used to create &pdvbdev;
|
||||
* @priv: private data
|
||||
* @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND,
|
||||
* %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA,
|
||||
* %DVB_DEVICE_NET
|
||||
* @type: type of the device, as defined by &enum dvb_device_type.
|
||||
* @demux_sink_pads: Number of demux outputs, to be used to create the TS
|
||||
* outputs via the Media Controller.
|
||||
*/
|
||||
@ -208,7 +230,7 @@ int dvb_register_device(struct dvb_adapter *adap,
|
||||
struct dvb_device **pdvbdev,
|
||||
const struct dvb_device *template,
|
||||
void *priv,
|
||||
int type,
|
||||
enum dvb_device_type type,
|
||||
int demux_sink_pads);
|
||||
|
||||
/**
|
||||
@ -246,7 +268,7 @@ void dvb_unregister_device(struct dvb_device *dvbdev);
|
||||
* dvb_create_media_graph - Creates media graph for the Digital TV part of the
|
||||
* device.
|
||||
*
|
||||
* @adap: pointer to struct dvb_adapter
|
||||
* @adap: pointer to &struct dvb_adapter
|
||||
* @create_rf_connector: if true, it creates the RF connector too
|
||||
*
|
||||
* 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,
|
||||
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,
|
||||
struct media_device *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;
|
||||
}
|
||||
@ -281,20 +314,131 @@ int dvb_create_media_graph(struct dvb_adapter *adap,
|
||||
#define dvb_get_media_controller(a) NULL
|
||||
#endif
|
||||
|
||||
int dvb_generic_open (struct inode *inode, struct file *file);
|
||||
int dvb_generic_release (struct inode *inode, struct file *file);
|
||||
long dvb_generic_ioctl (struct file *file,
|
||||
/**
|
||||
* dvb_generic_open - Digital TV open function, used by DVB devices
|
||||
*
|
||||
* @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);
|
||||
|
||||
/**
|
||||
* dvb_generic_close - Digital TV close function, used by DVB devices
|
||||
*
|
||||
* @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);
|
||||
|
||||
/* we don't mess with video_usercopy() any more,
|
||||
we simply define out own dvb_usercopy(), which will hopefully become
|
||||
generic_usercopy() someday... */
|
||||
|
||||
/**
|
||||
* 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 (*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
|
||||
/**
|
||||
* 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...) ({ \
|
||||
void *__r = NULL; \
|
||||
typeof(&FUNCTION) __a = symbol_request(FUNCTION); \
|
||||
@ -308,6 +452,14 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
__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)
|
||||
|
||||
#else
|
||||
@ -317,6 +469,6 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg,
|
||||
|
||||
#define dvb_detach(FUNC) {}
|
||||
|
||||
#endif
|
||||
#endif /* CONFIG_MEDIA_ATTACH */
|
||||
|
||||
#endif /* #ifndef _DVBDEV_H_ */
|
Loading…
Reference in New Issue
Block a user