diff --git a/Makefile b/Makefile index 6401060..28c954a 100644 --- a/Makefile +++ b/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* diff --git a/ddbridge/Kbuild b/ddbridge/Kbuild index 7cce364..bc9c7c5 100644 --- a/ddbridge/Kbuild +++ b/ddbridge/Kbuild @@ -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 \ No newline at end of file +#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 \ No newline at end of file diff --git a/ddbridge/Makefile b/ddbridge/Makefile index 1b286e2..f67e85b 100644 --- a/ddbridge/Makefile +++ b/ddbridge/Makefile @@ -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/ diff --git a/ddbridge/ddbridge-ci.c b/ddbridge/ddbridge-ci.c index a0cd6d8..99d5a1f 100644 --- a/ddbridge/ddbridge-ci.c +++ b/ddbridge/ddbridge-ci.c @@ -329,7 +329,7 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) case DDB_CI_EXTERNAL_XO2_B: ci_xo2_attach(port); break; - + case DDB_CI_INTERNAL: ci_attach(port); break; diff --git a/ddbridge/ddbridge-core.c b/ddbridge/ddbridge-core.c index 9fe0e29..d911837 100644 --- a/ddbridge/ddbridge-core.c +++ b/ddbridge/ddbridge-core.c @@ -24,7 +24,7 @@ #include "ddbridge.h" #include "ddbridge-i2c.h" #include "ddbridge-io.h" -#include "dvb_net.h" +#include 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,20 +1033,20 @@ 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 | - FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | - FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION + FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION }, .release = dummy_release, .read_status = dummy_read_status, @@ -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"; @@ -2286,7 +2161,7 @@ static int ddb_port_attach(struct ddb_port *port) if (ret < 0) break; /* fallthrough */ - case DDB_PORT_LOOP: + case DDB_PORT_LOOP: ret = dvb_register_device(port->dvb[0].adap, &port->dvb[0].dev, &dvbdev_ci, (void *)port->output, @@ -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; - - if ( cur_counter < (packet_loss & 0xFFFF) ) + u32 cur_counter = ddbreadl(dev, TS_STAT(input)) & 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); diff --git a/ddbridge/ddbridge-hw.c b/ddbridge/ddbridge-hw.c index c778962..af34a1e 100644 --- a/ddbridge/ddbridge-hw.c +++ b/ddbridge/ddbridge-hw.c @@ -801,7 +801,7 @@ static const struct ddb_device_id ddb_device_ids[] = { DDB_DEVID(0x0013, 0x0044, ddb_ci_s2_pro_a), DDB_DEVID(0x0020, 0x0012, ddb_gtl_mini), - /* Modulators */ + /* Modulators */ DDB_DEVID(0x0201, 0x0001, ddb_mod), DDB_DEVID(0x0201, 0x0002, ddb_mod), DDB_DEVID(0x0201, 0x0004, ddb_mod_4), /* dummy entry ! */ @@ -827,10 +827,10 @@ const struct ddb_info *get_ddb_info(u16 vendor, u16 device, u16 subvendor, u16 subdevice) { int i; - + for (i = 0; i < ARRAY_SIZE(ddb_device_ids); i++) { const struct ddb_device_id *id = &ddb_device_ids[i]; - + if (vendor == id->vendor && device == id->device && subvendor == id->subvendor && diff --git a/ddbridge/ddbridge-i2c.c b/ddbridge/ddbridge-i2c.c index 20e8610..5a850ff 100644 --- a/ddbridge/ddbridge-i2c.c +++ b/ddbridge/ddbridge-i2c.c @@ -35,33 +35,30 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) stat = wait_for_completion_timeout(&i2c->completion, HZ); val = ddbreadl(dev, i2c->regs + I2C_COMMAND); if (stat == 0) { + 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); -#if 1 - { - u32 istat = ddbreadl(dev, INTERRUPT_STATUS); + dev_err(dev->dev, "DDBridge IRS %08x\n", istat); - dev_err(dev->dev, "DDBridge IRS %08x\n", istat); - if (i2c->link) { - u32 listat = - ddbreadl(dev, - DDB_LINK_TAG(i2c->link) | - INTERRUPT_STATUS); - dev_err(dev->dev, - "DDBridge link %u IRS %08x\n", - i2c->link, listat); - } - if (istat & 1) { - ddbwritel(dev, istat & 1, INTERRUPT_ACK); - } else { - u32 mon = ddbreadl(dev, - i2c->regs + I2C_MONITOR); - - dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n", - val, mon); - } + if (i2c->link) { + u32 listat = + ddbreadl(dev, + DDB_LINK_TAG(i2c->link) | + INTERRUPT_STATUS); + dev_err(dev->dev, + "DDBridge link %u IRS %08x\n", + i2c->link, listat); + } + if (istat & 1) { + ddbwritel(dev, istat & 1, INTERRUPT_ACK); + } else { + u32 mon = ddbreadl(dev, + i2c->regs + I2C_MONITOR); + + dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n", + val, mon); } -#endif return -EIO; } val &= 0x70000; diff --git a/ddbridge/ddbridge-i2c.h b/ddbridge/ddbridge-i2c.h index 135704f..d21911a 100644 --- a/ddbridge/ddbridge-i2c.h +++ b/ddbridge/ddbridge-i2c.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * ddbridge-i2c.h: Digital Devices bridge i2c driver * diff --git a/ddbridge/ddbridge-io.c b/ddbridge/ddbridge-io.c index 4c696f3..8844a24 100644 --- a/ddbridge/ddbridge-io.c +++ b/ddbridge/ddbridge-io.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ddbridge-io.c: Digital Devices bridge I/O functions * diff --git a/ddbridge/ddbridge-io.h b/ddbridge/ddbridge-io.h index 7626ff8..283fef5 100644 --- a/ddbridge/ddbridge-io.h +++ b/ddbridge/ddbridge-io.h @@ -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; diff --git a/ddbridge/ddbridge-m4.c b/ddbridge/ddbridge-m4.c index e0cd533..1b29312 100644 --- a/ddbridge/ddbridge-m4.c +++ b/ddbridge/ddbridge-m4.c @@ -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,21 +473,21 @@ 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 | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | - FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION + FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION }, .release = release, .get_frontend_algo = get_algo, diff --git a/ddbridge/ddbridge-main.c b/ddbridge/ddbridge-main.c index 0ed622b..94da972 100644 --- a/ddbridge/ddbridge-main.c +++ b/ddbridge/ddbridge-main.c @@ -360,17 +360,17 @@ static int __devinit ddb_probe(struct pci_dev *pdev, if (dev->link[0].info->type == DDB_MOD && dev->link[0].info->version == 2) { u32 lic = ddbreadl(dev, 0x1c) & 7; - + switch (lic) { - case 0: + case 0: dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0000); break; - case 1: + case 1: dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0003); break; - case 3: + case 3: dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0002); break; @@ -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; diff --git a/ddbridge/ddbridge-max.c b/ddbridge/ddbridge-max.c index 9a58602..8816afe 100644 --- a/ddbridge/ddbridge-max.c +++ b/ddbridge/ddbridge-max.c @@ -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; @@ -502,7 +500,7 @@ int ddb_fe_attach_mci(struct ddb_input *input, u32 type) int demod, tuner; struct mci_cfg cfg; int fm = fmode; - + demod = input->nr; tuner = demod & 3; switch (type) { diff --git a/ddbridge/ddbridge-mci.c b/ddbridge/ddbridge-mci.c index a5683a0..66ad2f5 100644 --- a/ddbridge/ddbridge-mci.c +++ b/ddbridge/ddbridge-mci.c @@ -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); @@ -71,7 +72,7 @@ static int ddb_mci_cmd_raw_unlocked(struct mci *state, struct ddb_link *link = state->base->link; u32 i, val; unsigned long stat; - + val = ddblreadl(link, MCI_CONTROL); if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND)) return -EIO; @@ -80,19 +81,21 @@ static int ddb_mci_cmd_raw_unlocked(struct mci *state, ddblwritel(link, cmd[i], MCI_COMMAND + i * 4); val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT); ddblwritel(link, val, MCI_CONTROL); - + stat = wait_for_completion_timeout(&state->base->completion, HZ); 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); - if (istat & 1) + 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) ddbwritel(link->dev, 0xffffff, INTERRUPT_ACK); @@ -110,7 +113,7 @@ int ddb_mci_cmd_unlocked(struct mci *state, { u32 *cmd = (u32 *) command; u32 *res = (u32 *) result; - + return ddb_mci_cmd_raw_unlocked(state, cmd, sizeof(*command)/sizeof(u32), res, sizeof(*result)/sizeof(u32)); } @@ -141,7 +144,7 @@ int ddb_mci_cmd_raw(struct mci *state, struct mci_result *result, u32 result_len) { int stat; - + mutex_lock(&state->base->mci_lock); stat = ddb_mci_cmd_raw_unlocked(state, (u32 *)command, command_len, @@ -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; } @@ -249,7 +251,7 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_10, ROLLOFF_5, ROLLOFF_15, ROLLOFF_35, ROLLOFF_35 }; - + p->frequency = mci->signal_info.dvbs2_signal_info.frequency; switch (p->delivery_system) { @@ -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 = @@ -267,11 +268,10 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) SYS_DVBS2 : SYS_DVBS; if (mci->signal_info.dvbs2_signal_info.standard == 2) { u32 modcod = (0x7c & pls_code) >> 2; - + 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; diff --git a/ddbridge/ddbridge-mci.h b/ddbridge/ddbridge-mci.h index a1b2fa9..8ed3a58 100644 --- a/ddbridge/ddbridge-mci.h +++ b/ddbridge/ddbridge-mci.h @@ -644,14 +644,13 @@ struct mci_result { u8 min_input_stream_id; u8 max_input_stream_id; } BBHeader; - + 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 + 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; - + struct { u8 Change; // 5 bits, increments with every change struct { @@ -710,7 +709,7 @@ struct mci_result { /* DVB-T2 L1-Post Signalling Data ( ETSI EN 302 755 V1.4.1 Chapter 7.2.3 ) */ -#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 diff --git a/ddbridge/ddbridge-ns.c b/ddbridge/ddbridge-ns.c index 16a0700..57c7cf7 100644 --- a/ddbridge/ddbridge-ns.c +++ b/ddbridge/ddbridge-ns.c @@ -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; } diff --git a/ddbridge/ddbridge-sx8.c b/ddbridge/ddbridge-sx8.c index 9f4c017..d3bc223 100644 --- a/ddbridge/ddbridge-sx8.c +++ b/ddbridge/ddbridge-sx8.c @@ -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 | diff --git a/ddbridge/ddbridge.h b/ddbridge/ddbridge.h index 51f47cd..4ee5252 100644 --- a/ddbridge/ddbridge.h +++ b/ddbridge/ddbridge.h @@ -60,22 +60,20 @@ #include #include #include -#include #include #include #include #include -#include #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 +#include +#include +#include +#include +#include +#include #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); diff --git a/ddbridge/dvb_netstream.h b/ddbridge/dvb_netstream.h index a40f1f1..ca2a0a5 100644 --- a/ddbridge/dvb_netstream.h +++ b/ddbridge/dvb_netstream.h @@ -38,7 +38,7 @@ #include #include -#include "dvbdev.h" +#include #define DVBNS_MAXPIDS 32 diff --git a/dvb-core/Kconfig b/dvb-core/Kconfig index e7b2bdd..6ffac61 100644 --- a/dvb-core/Kconfig +++ b/dvb-core/Kconfig @@ -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. diff --git a/dvb-core/Makefile b/dvb-core/Makefile index c8a5f48..28e3437 100644 --- a/dvb-core/Makefile +++ b/dvb-core/Makefile @@ -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 diff --git a/dvb-core/Makefile.kernel b/dvb-core/Makefile.kernel index 8f22bcd..51d161a 100644 --- a/dvb-core/Makefile.kernel +++ b/dvb-core/Makefile.kernel @@ -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/ diff --git a/dvb-core/dmxdev.c b/dvb-core/dmxdev.c index eade5a7..6d09853 100644 --- a/dvb-core/dmxdev.c +++ b/dvb-core/dmxdev.c @@ -18,6 +18,7 @@ #define pr_fmt(fmt) "dmxdev: " fmt +#include #include #include #include @@ -27,8 +28,10 @@ #include #include #include -#include -#include "dmxdev.h" +#include +#ifdef CONFIG_DVB_MMAP +#include +#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,19 +488,40 @@ 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; - if (buffer->error) { - spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&buffer->queue); - return 0; +#ifdef CONFIG_DVB_MMAP + ctx = &dmxdevfilter->dev->dvr_vb2_ctx; +#endif } - ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); - if (ret == buffer1_len) - ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); + +#ifdef CONFIG_DVB_MMAP + if (dvb_vb2_is_streaming(ctx)) { + ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len, + buffer_flags); + if (ret == buffer1_len) + ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len, + buffer_flags); + } else { +#endif + if (buffer->error) { + spin_unlock(&dmxdevfilter->dev->lock); + wake_up(&buffer->queue); + return 0; + } + ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); + if (ret == buffer1_len) + ret = dvb_dmxdev_buffer_write(buffer, + buffer2, buffer2_len); +#ifdef CONFIG_DVB_MMAP + } +#endif if (ret < 0) 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; diff --git a/dvb-core/dmxdev.h b/dvb-core/dmxdev.h deleted file mode 100644 index 054fd4e..0000000 --- a/dvb-core/dmxdev.h +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#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_ */ diff --git a/dvb-core/dvb_ca_en50221.c b/dvb-core/dvb_ca_en50221.c index 87db54f..c398c39 100644 --- a/dvb-core/dvb_ca_en50221.c +++ b/dvb-core/dvb_ca_en50221.c @@ -34,8 +34,8 @@ #endif #include -#include "dvb_ca_en50221.h" -#include "dvb_ringbuffer.h" +#include +#include static int dvb_ca_en50221_debug; diff --git a/dvb-core/dvb_demux.c b/dvb-core/dvb_demux.c index 5083a54..44c5fd2 100644 --- a/dvb-core/dvb_demux.c +++ b/dvb-core/dvb_demux.c @@ -35,7 +35,7 @@ #include #include -#include "dvb_demux.h" +#include #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,8 +192,10 @@ 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 { @@ -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", - n, sec->tsfeedp); - dprintk("dvb_demux.c pad data:"); - for (i = 0; i < n; i++) - pr_cont(" %02x", sec->secbuf[i]); - pr_cont("\n"); + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("section ts padding loss: %d/%d\n", + n, sec->tsfeedp); + 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", - sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, - DMX_MAX_SECFEED_SIZE); -#endif + 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); 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,9 +449,10 @@ 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); - dprintk("TS speed %llu Kbits/sec \n", - div64_u64(speed_bytes, - speed_timedelta)); + if (speed_timedelta) + dprintk("TS speed %llu Kbits/sec \n", + div64_u64(speed_bytes, + speed_timedelta)); } demux->speed_last_time = cur_time; @@ -437,6 +461,11 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) } if (buf[1] & 0x80) { + 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; diff --git a/dvb-core/dvb_demux.h b/dvb-core/dvb_demux.h deleted file mode 100644 index 6f572ca..0000000 --- a/dvb-core/dvb_demux.h +++ /dev/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 -#include -#include -#include - -#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_ */ diff --git a/dvb-core/dvb_frontend.c b/dvb-core/dvb_frontend.c index 0d1b8d9..9f6ce4b 100644 --- a/dvb-core/dvb_frontend.c +++ b/dvb-core/dvb_frontend.c @@ -1,25 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * dvb_frontend.c: DVB frontend tuning interface/thread * - * * Copyright (C) 1999-2001 Ralph Metzler * Marcus Metzler * Holger Waechtler * for convergence integrated media GmbH * * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup) - * - * 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 */ /* Enables DVBv3 compatibility bits at the headers */ @@ -45,10 +33,11 @@ #include #include #include +#include #include -#include "dvb_frontend.h" -#include "dvbdev.h" +#include +#include #include static int dvb_frontend_debug; @@ -146,22 +135,39 @@ struct dvb_frontend_private { static void dvb_frontend_invoke_release(struct dvb_frontend *fe, void (*release)(struct dvb_frontend *fe)); -static void dvb_frontend_free(struct kref *ref) +static void __dvb_frontend_free(struct dvb_frontend *fe) { - struct dvb_frontend *fe = - container_of(ref, struct dvb_frontend, refcount); struct dvb_frontend_private *fepriv = fe->frontend_priv; - dvb_free_device(fepriv->dvbdev); + if (fepriv) + dvb_free_device(fepriv->dvbdev); dvb_frontend_invoke_release(fe, fe->ops.release); kfree(fepriv); } +static void dvb_frontend_free(struct kref *ref) +{ + struct dvb_frontend *fe = + container_of(ref, struct dvb_frontend, refcount); + + __dvb_frontend_free(fe); +} + static void dvb_frontend_put(struct dvb_frontend *fe) { - kref_put(&fe->refcount, dvb_frontend_free); + /* call detach before dropping the reference count */ + if (fe->ops.detach) + fe->ops.detach(fe); + /* + * Check if the frontend was registered, as otherwise + * kref was not initialized yet. + */ + if (fe->frontend_priv) + kref_put(&fe->refcount, dvb_frontend_free); + else + __dvb_frontend_free(fe); } static void dvb_frontend_get(struct dvb_frontend *fe) @@ -180,7 +186,7 @@ dtv_property_legacy_params_sync(struct dvb_frontend *fe, static bool has_get_frontend(struct dvb_frontend *fe) { - return fe->ops.get_frontend != NULL; + return fe->ops.get_frontend; } /* @@ -263,11 +269,23 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, mutex_unlock(&events->mtx); - wake_up_interruptible (&events->wait_queue); + wake_up_interruptible(&events->wait_queue); +} + +static int dvb_frontend_test_event(struct dvb_frontend_private *fepriv, + struct dvb_fe_events *events) +{ + int ret; + + up(&fepriv->sem); + ret = events->eventw != events->eventr; + down(&fepriv->sem); + + return ret; } static int dvb_frontend_get_event(struct dvb_frontend *fe, - struct dvb_frontend_event *event, int flags) + struct dvb_frontend_event *event, int flags) { struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_fe_events *events = &fepriv->events; @@ -285,13 +303,8 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, if (flags & O_NONBLOCK) return -EWOULDBLOCK; - up(&fepriv->sem); - - ret = wait_event_interruptible (events->wait_queue, - events->eventw != events->eventr); - - if (down_interruptible (&fepriv->sem)) - return -ERESTARTSYS; + ret = wait_event_interruptible(events->wait_queue, + dvb_frontend_test_event(fepriv, events)); if (ret < 0) return ret; @@ -318,8 +331,8 @@ static void dvb_frontend_clear_events(struct dvb_frontend *fe) static void dvb_frontend_init(struct dvb_frontend *fe) { dev_dbg(fe->dvb->device, - "%s: initialising adapter %i frontend %i (%s)...\n", - __func__, fe->dvb->num, fe->id, fe->ops.info.name); + "%s: initialising adapter %i frontend %i (%s)...\n", + __func__, fe->dvb->num, fe->id, fe->ops.info.name); if (fe->ops.init) fe->ops.init(fe); @@ -349,22 +362,25 @@ static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepr dev_dbg(fe->dvb->device, "%s:\n", __func__); if (locked) - (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256; + (fepriv->quality) = (fepriv->quality * 220 + 36 * 256) / 256; else (fepriv->quality) = (fepriv->quality * 220 + 0) / 256; q2 = fepriv->quality - 128; q2 *= q2; - fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128); + fepriv->delay = fepriv->min_delay + q2 * HZ / (128 * 128); } /** - * Performs automatic twiddling of frontend parameters. + * dvb_frontend_swzigzag_autotune - Performs automatic twiddling of frontend + * parameters. * - * @param fe The frontend concerned. - * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT - * @returns Number of complete iterations that have been performed. + * @fe: The frontend concerned. + * @check_wrapped: Checks if an iteration has completed. + * DO NOT SET ON THE FIRST ATTEMPT. + * + * return: Number of complete iterations that have been performed. */ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped) { @@ -381,7 +397,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra (c->inversion == INVERSION_AUTO)); /* setup parameters correctly */ - while(!ready) { + while (!ready) { /* calculate the lnb_drift */ fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size; @@ -393,7 +409,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra } /* perform inversion and +/- zigzag */ - switch(fepriv->auto_sub_step) { + switch (fepriv->auto_sub_step) { case 0: /* try with the current inversion and current drift setting */ ready = 1; @@ -438,11 +454,11 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra return 1; } - dev_dbg(fe->dvb->device, "%s: drift:%i inversion:%i auto_step:%i " \ - "auto_sub_step:%i started_auto_step:%i\n", - __func__, fepriv->lnb_drift, fepriv->inversion, - fepriv->auto_step, fepriv->auto_sub_step, - fepriv->started_auto_step); + dev_dbg(fe->dvb->device, + "%s: drift:%i inversion:%i auto_step:%i auto_sub_step:%i started_auto_step:%i\n", + __func__, fepriv->lnb_drift, fepriv->inversion, + fepriv->auto_step, fepriv->auto_sub_step, + fepriv->started_auto_step); /* set the frontend itself */ c->frequency += fepriv->lnb_drift; @@ -473,7 +489,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) /* if we've got no parameters, just keep idling */ if (fepriv->state & FESTATE_IDLE) { - fepriv->delay = 3*HZ; + fepriv->delay = 3 * HZ; fepriv->quality = 0; return; } @@ -490,7 +506,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) else fepriv->state = FESTATE_TUNED; } - fepriv->delay = 3*HZ; + fepriv->delay = 3 * HZ; fepriv->quality = 0; return; } @@ -579,7 +595,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) } fepriv->check_wrapped = 1; - /* if we've just retuned, enter the ZIGZAG_FAST state. + /* if we've just re-tuned, enter the ZIGZAG_FAST state. * This ensures we cannot return from an * FE_SET_FRONTEND ioctl before the first frontend tune * occurs */ @@ -646,7 +662,7 @@ static int dvb_frontend_thread(void *data) fepriv->check_wrapped = 0; fepriv->quality = 0; - fepriv->delay = 3*HZ; + fepriv->delay = 3 * HZ; fepriv->status = 0; fepriv->wakeup = 0; fepriv->reinitialise = 0; @@ -658,8 +674,9 @@ static int dvb_frontend_thread(void *data) up(&fepriv->sem); /* is locked when we enter the thread... */ restart: wait_event_interruptible_timeout(fepriv->wait_queue, - dvb_frontend_should_wakeup(fe) || kthread_should_stop() - || freezing(current), + dvb_frontend_should_wakeup(fe) || + kthread_should_stop() || + freezing(current), fepriv->delay); if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { @@ -808,8 +825,8 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) /* paranoia check in case a signal arrived */ if (fepriv->thread) dev_warn(fe->dvb->device, - "dvb_frontend_stop: warning: thread %p won't exit\n", - fepriv->thread); + "dvb_frontend_stop: warning: thread %p won't exit\n", + fepriv->thread); } /* @@ -846,12 +863,12 @@ static int dvb_frontend_start(struct dvb_frontend *fe) if (fe->exit == DVB_FE_NO_EXIT) return 0; else - dvb_frontend_stop (fe); + dvb_frontend_stop(fe); } if (signal_pending(current)) return -EINTR; - if (down_interruptible (&fepriv->sem)) + if (down_interruptible(&fepriv->sem)) return -EINTR; fepriv->state = FESTATE_IDLE; @@ -860,12 +877,12 @@ static int dvb_frontend_start(struct dvb_frontend *fe) mb(); fe_thread = kthread_run(dvb_frontend_thread, fe, - "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id); + "kdvb-ad-%i-fe-%i", fe->dvb->num, fe->id); if (IS_ERR(fe_thread)) { ret = PTR_ERR(fe_thread); dev_warn(fe->dvb->device, - "dvb_frontend_start: failed to start kthread (%d)\n", - ret); + "dvb_frontend_start: failed to start kthread (%d)\n", + ret); up(&fepriv->sem); return ret; } @@ -874,20 +891,70 @@ static int dvb_frontend_start(struct dvb_frontend *fe) } static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe, - u32 *freq_min, u32 *freq_max) + u32 *freq_min, u32 *freq_max, + u32 *tolerance) { - *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 tuner_min = fe->ops.tuner_ops.info.frequency_min_hz; + u32 tuner_max = fe->ops.tuner_ops.info.frequency_max_hz; + u32 frontend_min = fe->ops.info.frequency_min_hz; + u32 frontend_max = fe->ops.info.frequency_max_hz; - if (fe->ops.info.frequency_max == 0) - *freq_max = fe->ops.tuner_ops.info.frequency_max; - else if (fe->ops.tuner_ops.info.frequency_max == 0) - *freq_max = fe->ops.info.frequency_max; + *freq_min = max(frontend_min, tuner_min); + + if (frontend_max == 0) + *freq_max = tuner_max; + else if (tuner_max == 0) + *freq_max = frontend_max; else - *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); + *freq_max = min(frontend_max, tuner_max); if (*freq_min == 0 || *freq_max == 0) - dev_warn(fe->dvb->device, "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n", - fe->dvb->num, fe->id); + dev_warn(fe->dvb->device, + "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n", + fe->dvb->num, fe->id); + + dev_dbg(fe->dvb->device, "frequency interval: tuner: %u...%u, frontend: %u...%u", + tuner_min, tuner_max, frontend_min, frontend_max); + + /* If the standard is for satellite, convert frequencies to kHz */ + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + case SYS_ISDBS: + *freq_min /= kHz; + *freq_max /= kHz; + if (tolerance) + *tolerance = fe->ops.info.frequency_tolerance_hz / kHz; + + break; + default: + if (tolerance) + *tolerance = fe->ops.info.frequency_tolerance_hz; + break; + } +} + +static u32 dvb_frontend_get_stepsize(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 fe_step = fe->ops.info.frequency_stepsize_hz; + u32 tuner_step = fe->ops.tuner_ops.info.frequency_step_hz; + u32 step = max(fe_step, tuner_step); + + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + case SYS_ISDBS: + step /= kHz; + break; + default: + break; + } + + return step; } static int dvb_frontend_check_parameters(struct dvb_frontend *fe) @@ -897,12 +964,12 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe) u32 freq_max; /* range check: frequency */ - dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max); + dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max, NULL); if ((freq_min && c->frequency < freq_min) || (freq_max && c->frequency > freq_max)) { dev_warn(fe->dvb->device, "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, c->frequency, - freq_min, freq_max); + fe->dvb->num, fe->id, c->frequency, + freq_min, freq_max); return -EINVAL; } @@ -918,9 +985,9 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe) (fe->ops.info.symbol_rate_max && c->symbol_rate > fe->ops.info.symbol_rate_max)) { dev_warn(fe->dvb->device, "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, c->symbol_rate, - fe->ops.info.symbol_rate_min, - fe->ops.info.symbol_rate_max); + fe->dvb->num, fe->id, c->symbol_rate, + fe->ops.info.symbol_rate_min, + fe->ops.info.symbol_rate_max); return -EINVAL; } default: @@ -940,10 +1007,8 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) memset(c, 0, offsetof(struct dtv_frontend_properties, strength)); c->delivery_system = delsys; - c->state = DTV_CLEAR; - dev_dbg(fe->dvb->device, "%s: Clearing cache for delivery system %d\n", - __func__, c->delivery_system); + __func__, c->delivery_system); c->transmission_mode = TRANSMISSION_MODE_AUTO; c->bandwidth_hz = 0; /* AUTO */ @@ -963,7 +1028,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) c->isdbt_sb_subchannel = 0; c->isdbt_sb_segment_idx = 0; c->isdbt_sb_segment_count = 0; - c->isdbt_layer_enabled = 0; + c->isdbt_layer_enabled = 7; /* All layers (A,B,C) */ for (i = 0; i < 3; i++) { c->layer[i].fec = FEC_AUTO; c->layer[i].modulation = QAM_AUTO; @@ -1102,39 +1167,6 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0), }; -static void dtv_property_dump(struct dvb_frontend *fe, - bool is_set, - struct dtv_property *tvp) -{ - int i; - - if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { - dev_warn(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x undefined\n", - __func__, - is_set ? "SET" : "GET", - tvp->cmd); - return; - } - - dev_dbg(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x (%s)\n", __func__, - is_set ? "SET" : "GET", - tvp->cmd, - dtv_cmds[tvp->cmd].name); - - if (dtv_cmds[tvp->cmd].buffer) { - dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n", - __func__, tvp->u.buffer.len); - - for(i = 0; i < tvp->u.buffer.len; i++) - dev_dbg(fe->dvb->device, - "%s: tvp.u.buffer.data[0x%02x] = 0x%02x\n", - __func__, i, tvp->u.buffer.data[i]); - } else { - dev_dbg(fe->dvb->device, "%s: tvp.u.data = 0x%08x\n", __func__, - tvp->u.data); - } -} - /* Synchronise the legacy tuning parameters into the cache, so that demodulator * drivers can use a single set_frontend tuning function, regardless of whether * it's being used for the legacy or new API, reducing code and complexity. @@ -1203,8 +1235,8 @@ static int dtv_property_cache_sync(struct dvb_frontend *fe, break; case DVBV3_UNKNOWN: dev_err(fe->dvb->device, - "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", - __func__, c->delivery_system); + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); return -EINVAL; } @@ -1225,8 +1257,8 @@ dtv_property_legacy_params_sync(struct dvb_frontend *fe, switch (dvbv3_type(c->delivery_system)) { case DVBV3_UNKNOWN: dev_err(fe->dvb->device, - "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", - __func__, c->delivery_system); + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); return -EINVAL; case DVBV3_QPSK: dev_dbg(fe->dvb->device, "%s: Preparing QPSK req\n", __func__); @@ -1283,7 +1315,7 @@ dtv_property_legacy_params_sync(struct dvb_frontend *fe, * dtv_get_frontend - calls a callback for retrieving DTV parameters * @fe: struct dvb_frontend pointer * @c: struct dtv_frontend_properties pointer (DVBv5 cache) - * @p_out struct dvb_frontend_parameters pointer (DVBv3 FE struct) + * @p_out: struct dvb_frontend_parameters pointer (DVBv3 FE struct) * * This routine calls either the DVBv3 or DVBv5 get_frontend call. * If c is not null, it will update the DVBv5 cache struct pointed by it. @@ -1308,17 +1340,15 @@ static int dtv_get_frontend(struct dvb_frontend *fe, return 0; } -static int dvb_frontend_ioctl_legacy(struct file *file, - unsigned int cmd, void *parg); -static int dvb_frontend_ioctl_properties(struct file *file, - unsigned int cmd, void *parg); +static int dvb_frontend_handle_ioctl(struct file *file, + unsigned int cmd, void *parg); static int dtv_property_process_get(struct dvb_frontend *fe, const struct dtv_frontend_properties *c, struct dtv_property *tvp, struct file *file) { - int r, ncaps; + int ncaps; switch(tvp->cmd) { case DTV_ENUM_DELSYS: @@ -1446,6 +1476,11 @@ static int dtv_property_process_get(struct dvb_frontend *fe, tvp->u.data = c->stream_id; break; + /* Physical layer scrambling support */ + case DTV_SCRAMBLING_SEQUENCE_INDEX: + tvp->u.data = c->scrambling_sequence_index; + break; + /* ATSC-MH */ case DTV_ATSCMH_FIC_VER: tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver; @@ -1505,11 +1540,6 @@ static int dtv_property_process_get(struct dvb_frontend *fe, tvp->u.buffer.len = 4; break; - /* Physical layer scrambling support */ - case DTV_SCRAMBLING_SEQUENCE_INDEX: - tvp->u.data = c->scrambling_sequence_index; - break; - /* Fill quality measures */ case DTV_STAT_SIGNAL_STRENGTH: tvp->u.st = c->strength; @@ -1542,14 +1572,18 @@ static int dtv_property_process_get(struct dvb_frontend *fe, return -EINVAL; } - /* Allow the frontend to override outgoing properties */ - if (fe->ops.get_property) { - r = fe->ops.get_property(fe, tvp); - if (r < 0) - return r; - } - - dtv_property_dump(fe, false, tvp); + if (!dtv_cmds[tvp->cmd].buffer) + dev_dbg(fe->dvb->device, + "%s: GET cmd 0x%08x (%s) = 0x%08x\n", + __func__, tvp->cmd, dtv_cmds[tvp->cmd].name, + tvp->u.data); + else + dev_dbg(fe->dvb->device, + "%s: GET cmd 0x%08x (%s) len %d: %*ph\n", + __func__, + tvp->cmd, dtv_cmds[tvp->cmd].name, + tvp->u.buffer.len, + tvp->u.buffer.len, tvp->u.buffer.data); return 0; } @@ -1569,7 +1603,7 @@ static bool is_dvbv3_delsys(u32 delsys) * * Provides emulation for delivery systems that are compatible with the old * DVBv3 call. Among its usages, it provices support for ISDB-T, and allows - * using a DVB-S2 only frontend just like it were a DVB-S, if the frontent + * using a DVB-S2 only frontend just like it were a DVB-S, if the frontend * parameters are compatible with DVB-S spec. */ static int emulate_delivery_system(struct dvb_frontend *fe, u32 delsys) @@ -1653,8 +1687,8 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe, if (fe->ops.delsys[ncaps] == desired_system) { c->delivery_system = desired_system; dev_dbg(fe->dvb->device, - "%s: Changing delivery system to %d\n", - __func__, desired_system); + "%s: Changing delivery system to %d\n", + __func__, desired_system); return 0; } ncaps++; @@ -1746,8 +1780,8 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) */ if (is_dvbv3_delsys(c->delivery_system)) { dev_dbg(fe->dvb->device, - "%s: Using delivery system to %d\n", - __func__, c->delivery_system); + "%s: Using delivery system to %d\n", + __func__, c->delivery_system); return 0; } @@ -1772,169 +1806,187 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) return emulate_delivery_system(fe, delsys); } +/** + * dtv_property_process_set - Sets a single DTV property + * @fe: Pointer to &struct dvb_frontend + * @file: Pointer to &struct file + * @cmd: Digital TV command + * @data: An unsigned 32-bits number + * + * This routine assigns the property + * value to the corresponding member of + * &struct dtv_frontend_properties + * + * Returns: + * Zero on success, negative errno on failure. + */ static int dtv_property_process_set(struct dvb_frontend *fe, - struct dtv_property *tvp, - struct file *file) + struct file *file, + u32 cmd, u32 data) { int r = 0; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - /* Allow the frontend to validate incoming properties */ - if (fe->ops.set_property) { - r = fe->ops.set_property(fe, tvp); - if (r < 0) - return r; - } - - dtv_property_dump(fe, true, tvp); - - switch(tvp->cmd) { + /** Dump DTV command name and value*/ + if (!cmd || cmd > DTV_MAX_COMMAND) + dev_warn(fe->dvb->device, "%s: SET cmd 0x%08x undefined\n", + __func__, cmd); + else + dev_dbg(fe->dvb->device, + "%s: SET cmd 0x%08x (%s) to 0x%08x\n", + __func__, cmd, dtv_cmds[cmd].name, data); + switch (cmd) { case DTV_CLEAR: /* * Reset a cache of data specific to the frontend here. This does - * not affect hardware. + * not effect hardware. */ dvb_frontend_clear_cache(fe); break; case DTV_TUNE: - /* interpret the cache of data, build either a traditional frontend - * tunerequest so we can pass validation in the FE_SET_FRONTEND - * ioctl. + /* + * Use the cached Digital TV properties to tune the + * frontend */ - c->state = tvp->cmd; - dev_dbg(fe->dvb->device, "%s: Finalised property cache\n", - __func__); + dev_dbg(fe->dvb->device, + "%s: Setting the frontend from property cache\n", + __func__); r = dtv_set_frontend(fe); break; case DTV_FREQUENCY: - c->frequency = tvp->u.data; + c->frequency = data; break; case DTV_MODULATION: - c->modulation = tvp->u.data; + c->modulation = data; break; case DTV_BANDWIDTH_HZ: - c->bandwidth_hz = tvp->u.data; + c->bandwidth_hz = data; break; case DTV_INVERSION: - c->inversion = tvp->u.data; + c->inversion = data; break; case DTV_SYMBOL_RATE: - c->symbol_rate = tvp->u.data; + c->symbol_rate = data; break; case DTV_INNER_FEC: - c->fec_inner = tvp->u.data; + c->fec_inner = data; break; case DTV_PILOT: - c->pilot = tvp->u.data; + c->pilot = data; break; case DTV_ROLLOFF: - c->rolloff = tvp->u.data; + c->rolloff = data; break; case DTV_DELIVERY_SYSTEM: - r = dvbv5_set_delivery_system(fe, tvp->u.data); + r = dvbv5_set_delivery_system(fe, data); break; case DTV_VOLTAGE: - c->voltage = tvp->u.data; - r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE, - (void *)c->voltage); + c->voltage = data; + r = dvb_frontend_handle_ioctl(file, FE_SET_VOLTAGE, + (void *)c->voltage); break; case DTV_TONE: - c->sectone = tvp->u.data; - r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE, - (void *)c->sectone); + c->sectone = data; + r = dvb_frontend_handle_ioctl(file, FE_SET_TONE, + (void *)c->sectone); break; case DTV_CODE_RATE_HP: - c->code_rate_HP = tvp->u.data; + c->code_rate_HP = data; break; case DTV_CODE_RATE_LP: - c->code_rate_LP = tvp->u.data; + c->code_rate_LP = data; break; case DTV_GUARD_INTERVAL: - c->guard_interval = tvp->u.data; + c->guard_interval = data; break; case DTV_TRANSMISSION_MODE: - c->transmission_mode = tvp->u.data; + c->transmission_mode = data; break; case DTV_HIERARCHY: - c->hierarchy = tvp->u.data; + c->hierarchy = data; break; case DTV_INTERLEAVING: - c->interleaving = tvp->u.data; + c->interleaving = data; break; /* ISDB-T Support here */ case DTV_ISDBT_PARTIAL_RECEPTION: - c->isdbt_partial_reception = tvp->u.data; + c->isdbt_partial_reception = data; break; case DTV_ISDBT_SOUND_BROADCASTING: - c->isdbt_sb_mode = tvp->u.data; + c->isdbt_sb_mode = data; break; case DTV_ISDBT_SB_SUBCHANNEL_ID: - c->isdbt_sb_subchannel = tvp->u.data; + c->isdbt_sb_subchannel = data; break; case DTV_ISDBT_SB_SEGMENT_IDX: - c->isdbt_sb_segment_idx = tvp->u.data; + c->isdbt_sb_segment_idx = data; break; case DTV_ISDBT_SB_SEGMENT_COUNT: - c->isdbt_sb_segment_count = tvp->u.data; + c->isdbt_sb_segment_count = data; break; case DTV_ISDBT_LAYER_ENABLED: - c->isdbt_layer_enabled = tvp->u.data; + c->isdbt_layer_enabled = data; break; case DTV_ISDBT_LAYERA_FEC: - c->layer[0].fec = tvp->u.data; + c->layer[0].fec = data; break; case DTV_ISDBT_LAYERA_MODULATION: - c->layer[0].modulation = tvp->u.data; + c->layer[0].modulation = data; break; case DTV_ISDBT_LAYERA_SEGMENT_COUNT: - c->layer[0].segment_count = tvp->u.data; + c->layer[0].segment_count = data; break; case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: - c->layer[0].interleaving = tvp->u.data; + c->layer[0].interleaving = data; break; case DTV_ISDBT_LAYERB_FEC: - c->layer[1].fec = tvp->u.data; + c->layer[1].fec = data; break; case DTV_ISDBT_LAYERB_MODULATION: - c->layer[1].modulation = tvp->u.data; + c->layer[1].modulation = data; break; case DTV_ISDBT_LAYERB_SEGMENT_COUNT: - c->layer[1].segment_count = tvp->u.data; + c->layer[1].segment_count = data; break; case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: - c->layer[1].interleaving = tvp->u.data; + c->layer[1].interleaving = data; break; case DTV_ISDBT_LAYERC_FEC: - c->layer[2].fec = tvp->u.data; + c->layer[2].fec = data; break; case DTV_ISDBT_LAYERC_MODULATION: - c->layer[2].modulation = tvp->u.data; + c->layer[2].modulation = data; break; case DTV_ISDBT_LAYERC_SEGMENT_COUNT: - c->layer[2].segment_count = tvp->u.data; + c->layer[2].segment_count = data; break; case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: - c->layer[2].interleaving = tvp->u.data; + c->layer[2].interleaving = data; break; /* Multistream support */ case DTV_STREAM_ID: case DTV_DVBT2_PLP_ID_LEGACY: - c->stream_id = tvp->u.data; + c->stream_id = data; + break; + + /* Physical layer scrambling support */ + case DTV_SCRAMBLING_SEQUENCE_INDEX: + c->scrambling_sequence_index = data; break; /* ATSC-MH */ case DTV_ATSCMH_PARADE_ID: - fe->dtv_property_cache.atscmh_parade_id = tvp->u.data; + fe->dtv_property_cache.atscmh_parade_id = data; break; case DTV_ATSCMH_RS_FRAME_ENSEMBLE: - fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data; + fe->dtv_property_cache.atscmh_rs_frame_ensemble = data; break; case DTV_LNA: - c->lna = tvp->u.data; + c->lna = data; if (fe->ops.set_lna) r = fe->ops.set_lna(fe); if (r < 0) @@ -1942,16 +1994,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe, break; case DTV_INPUT: - c->input = tvp->u.data; + c->input = data; if (fe->ops.set_input) r = fe->ops.set_input(fe, c->input); break; - /* Physical layer scrambling support */ - case DTV_SCRAMBLING_SEQUENCE_INDEX: - c->scrambling_sequence_index = tvp->u.data; - break; - default: return -EINVAL; } @@ -1959,14 +2006,13 @@ static int dtv_property_process_set(struct dvb_frontend *fe, return r; } -static int dvb_frontend_ioctl(struct file *file, - unsigned int cmd, void *parg) +static int dvb_frontend_do_ioctl(struct file *file, unsigned int cmd, + void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_private *fepriv = fe->frontend_priv; - int err = -EOPNOTSUPP; + int err; dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd)); if (down_interruptible(&fepriv->sem)) @@ -1977,74 +2023,125 @@ static int dvb_frontend_ioctl(struct file *file, return -ENODEV; } - if ((file->f_flags & O_ACCMODE) == O_RDONLY && - (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT || - cmd == FE_DISEQC_RECV_SLAVE_REPLY)) { + /* + * If the frontend is opened in read-only mode, only the ioctls + * that don't interfere with the tune logic should be accepted. + * That allows an external application to monitor the DVB QoS and + * statistics parameters. + * + * That matches all _IOR() ioctls, except for two special cases: + * - FE_GET_EVENT is part of the tuning logic on a DVB application; + * - FE_DISEQC_RECV_SLAVE_REPLY is part of DiSEqC 2.0 + * setup + * So, those two ioctls should also return -EPERM, as otherwise + * reading from them would interfere with a DVB tune application + */ + if ((file->f_flags & O_ACCMODE) == O_RDONLY + && (_IOC_DIR(cmd) != _IOC_READ + || cmd == FE_GET_EVENT + || cmd == FE_DISEQC_RECV_SLAVE_REPLY)) { up(&fepriv->sem); return -EPERM; } - if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) - err = dvb_frontend_ioctl_properties(file, cmd, parg); - else { - c->state = DTV_UNDEFINED; - err = dvb_frontend_ioctl_legacy(file, cmd, parg); - } + err = dvb_frontend_handle_ioctl(file, cmd, parg); up(&fepriv->sem); return err; } -static int dvb_frontend_ioctl_properties(struct file *file, - unsigned int cmd, void *parg) +static long dvb_frontend_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct dvb_device *dvbdev = file->private_data; + + if (!dvbdev) + return -ENODEV; + + return dvb_usercopy(file, cmd, arg, dvb_frontend_do_ioctl); +} + +#ifdef CONFIG_COMPAT +struct compat_dtv_property { + __u32 cmd; + __u32 reserved[3]; + union { + __u32 data; + struct dtv_fe_stats st; + struct { + __u8 data[32]; + __u32 len; + __u32 reserved1[3]; + compat_uptr_t reserved2; + } buffer; + } u; + int result; +} __attribute__ ((packed)); + +struct compat_dtv_properties { + __u32 num; + compat_uptr_t props; +}; + +#define COMPAT_FE_SET_PROPERTY _IOW('o', 82, struct compat_dtv_properties) +#define COMPAT_FE_GET_PROPERTY _IOR('o', 83, struct compat_dtv_properties) + +static int dvb_frontend_handle_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int err = 0; + int i, err = 0; - struct dtv_properties *tvps = parg; - struct dtv_property *tvp = NULL; - int i; + if (cmd == COMPAT_FE_SET_PROPERTY) { + struct compat_dtv_properties prop, *tvps = NULL; + struct compat_dtv_property *tvp = NULL; - dev_dbg(fe->dvb->device, "%s:\n", __func__); + if (copy_from_user(&prop, compat_ptr(arg), sizeof(prop))) + return -EFAULT; - if (cmd == FE_SET_PROPERTY) { - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); + tvps = ∝ - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + tvp = memdup_user(compat_ptr(tvps->props), tvps->num * sizeof(*tvp)); if (IS_ERR(tvp)) return PTR_ERR(tvp); for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_set(fe, tvp + i, file); - if (err < 0) - goto out; - (tvp + i)->result = err; + err = dtv_property_process_set(fe, file, + (tvp + i)->cmd, + (tvp + i)->u.data); + if (err < 0) { + kfree(tvp); + return err; + } } - - if (c->state == DTV_TUNE) - dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); - - } else if (cmd == FE_GET_PROPERTY) { + kfree(tvp); + } else if (cmd == COMPAT_FE_GET_PROPERTY) { + struct compat_dtv_properties prop, *tvps = NULL; + struct compat_dtv_property *tvp = NULL; struct dtv_frontend_properties getp = fe->dtv_property_cache; - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); + if (copy_from_user(&prop, compat_ptr(arg), sizeof(prop))) + return -EFAULT; - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) + tvps = ∝ + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + tvp = memdup_user(compat_ptr(tvps->props), tvps->num * sizeof(*tvp)); if (IS_ERR(tvp)) return PTR_ERR(tvp); @@ -2056,30 +2153,53 @@ static int dvb_frontend_ioctl_properties(struct file *file, */ if (fepriv->state != FESTATE_IDLE) { err = dtv_get_frontend(fe, &getp, NULL); - if (err < 0) - goto out; + if (err < 0) { + kfree(tvp); + return err; + } } for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_get(fe, &getp, tvp + i, file); - if (err < 0) - goto out; - (tvp + i)->result = err; + err = dtv_property_process_get( + fe, &getp, (struct dtv_property *)(tvp + i), file); + if (err < 0) { + kfree(tvp); + return err; + } } - if (copy_to_user((void __user *)tvps->props, tvp, - tvps->num * sizeof(struct dtv_property))) { - err = -EFAULT; - goto out; + if (copy_to_user((void __user *)compat_ptr(tvps->props), tvp, + tvps->num * sizeof(struct compat_dtv_property))) { + kfree(tvp); + return -EFAULT; } + kfree(tvp); + } - } else - err = -EOPNOTSUPP; - -out: - kfree(tvp); return err; } +static long dvb_frontend_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + int err; + + if (cmd == COMPAT_FE_SET_PROPERTY || cmd == COMPAT_FE_GET_PROPERTY) { + if (down_interruptible(&fepriv->sem)) + return -ERESTARTSYS; + + err = dvb_frontend_handle_compat_ioctl(file, cmd, arg); + + up(&fepriv->sem); + return err; + } + + return dvb_frontend_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + static int dtv_set_frontend(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -2148,9 +2268,8 @@ static int dtv_set_frontend(struct dvb_frontend *fe) default: break; } - if (!c->bandwidth_hz) - if (rolloff) - c->bandwidth_hz = mult_frac(c->symbol_rate, rolloff, 100); + if (rolloff) + c->bandwidth_hz = mult_frac(c->symbol_rate, rolloff, 100); /* force auto frequency inversion if requested */ if (dvb_force_auto_inversion) @@ -2187,8 +2306,8 @@ static int dtv_set_frontend(struct dvb_frontend *fe) case SYS_ISDBT: case SYS_DTMB: fepriv->min_delay = HZ / 20; - fepriv->step_size = fe->ops.info.frequency_stepsize * 2; - fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; + fepriv->step_size = dvb_frontend_get_stepsize(fe) * 2; + fepriv->max_drift = (dvb_frontend_get_stepsize(fe) * 2) + 1; break; default: /* @@ -2218,21 +2337,144 @@ static int dtv_set_frontend(struct dvb_frontend *fe) } -static int dvb_frontend_ioctl_legacy(struct file *file, - unsigned int cmd, void *parg) +static int dvb_get_property(struct dvb_frontend *fe, struct file *file, + struct dtv_properties *tvps) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_property *tvp = NULL; + struct dtv_frontend_properties getp; + int i, err; + + memcpy(&getp, &fe->dtv_property_cache, sizeof(getp)); + + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || tvps->num > DTV_IOCTL_MAX_MSGS) + return -EINVAL; + + tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); + if (IS_ERR(tvp)) + return PTR_ERR(tvp); + + /* + * Let's use our own copy of property cache, in order to + * avoid mangling with DTV zigzag logic, as drivers might + * return crap, if they don't check if the data is available + * before updating the properties cache. + */ + if (fepriv->state != FESTATE_IDLE) { + err = dtv_get_frontend(fe, &getp, NULL); + if (err < 0) + goto out; + } + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_get(fe, &getp, + tvp + i, file); + if (err < 0) + goto out; + } + + if (copy_to_user((void __user *)tvps->props, tvp, + tvps->num * sizeof(struct dtv_property))) { + err = -EFAULT; + goto out; + } + + err = 0; +out: + kfree(tvp); + return err; +} + +static int dvb_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p_out) +{ + struct dtv_frontend_properties getp; + + /* + * Let's use our own copy of property cache, in order to + * avoid mangling with DTV zigzag logic, as drivers might + * return crap, if they don't check if the data is available + * before updating the properties cache. + */ + memcpy(&getp, &fe->dtv_property_cache, sizeof(getp)); + + return dtv_get_frontend(fe, &getp, p_out); +} + +static int dvb_frontend_handle_ioctl(struct file *file, + unsigned int cmd, void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int err = -EOPNOTSUPP; + int i, err = -ENOTSUPP; + + dev_dbg(fe->dvb->device, "%s:\n", __func__); switch (cmd) { - case FE_GET_INFO: { - struct dvb_frontend_info* info = parg; + case FE_SET_PROPERTY: { + struct dtv_properties *tvps = parg; + struct dtv_property *tvp = NULL; - memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); - dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) + return -EINVAL; + + tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); + if (IS_ERR(tvp)) + return PTR_ERR(tvp); + + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_set(fe, file, + (tvp + i)->cmd, + (tvp + i)->u.data); + if (err < 0) { + kfree(tvp); + return err; + } + } + kfree(tvp); + err = 0; + break; + } + case FE_GET_PROPERTY: + err = dvb_get_property(fe, file, parg); + break; + + case FE_GET_INFO: { + struct dvb_frontend_info *info = parg; + memset(info, 0, sizeof(*info)); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)) + strscpy(info->name, fe->ops.info.name, sizeof(info->name)); +#else + strncpy(info->name, fe->ops.info.name, sizeof(info->name)); +#endif + info->symbol_rate_min = fe->ops.info.symbol_rate_min; + info->symbol_rate_max = fe->ops.info.symbol_rate_max; + info->symbol_rate_tolerance = fe->ops.info.symbol_rate_tolerance; + info->caps = fe->ops.info.caps; + info->frequency_stepsize = dvb_frontend_get_stepsize(fe); + dvb_frontend_get_frequency_limits(fe, &info->frequency_min, + &info->frequency_max, + &info->frequency_tolerance); /* * Associate the 4 delivery systems supported by DVBv3 @@ -2260,12 +2502,12 @@ static int dvb_frontend_ioctl_legacy(struct file *file, break; default: dev_err(fe->dvb->device, - "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", - __func__, c->delivery_system); - fe->ops.info.type = FE_OFDM; + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + info->type = FE_OFDM; } dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n", - __func__, c->delivery_system, fe->ops.info.type); + __func__, c->delivery_system, info->type); /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */ if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) @@ -2281,7 +2523,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, * that user get signal state from previous tuning */ if (fepriv->state == FESTATE_RETUNE || fepriv->state == FESTATE_ERROR) { - err=0; + err = 0; *status = 0; break; } @@ -2291,42 +2533,6 @@ static int dvb_frontend_ioctl_legacy(struct file *file, break; } - case FE_READ_BER: - if (fe->ops.read_ber) { - if (fepriv->thread) - err = fe->ops.read_ber(fe, (__u32 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_SIGNAL_STRENGTH: - if (fe->ops.read_signal_strength) { - if (fepriv->thread) - err = fe->ops.read_signal_strength(fe, (__u16 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_SNR: - if (fe->ops.read_snr) { - if (fepriv->thread) - err = fe->ops.read_snr(fe, (__u16 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_UNCORRECTED_BLOCKS: - if (fe->ops.read_ucblocks) { - if (fepriv->thread) - err = fe->ops.read_ucblocks(fe, (__u32 *) parg); - else - err = -EAGAIN; - } - break; - case FE_DISEQC_RESET_OVERLOAD: if (fe->ops.diseqc_reset_overload) { err = fe->ops.diseqc_reset_overload(fe); @@ -2378,6 +2584,22 @@ static int dvb_frontend_ioctl_legacy(struct file *file, } break; + case FE_DISEQC_RECV_SLAVE_REPLY: + if (fe->ops.diseqc_recv_slave_reply) + err = fe->ops.diseqc_recv_slave_reply(fe, parg); + break; + + case FE_ENABLE_HIGH_LNB_VOLTAGE: + if (fe->ops.enable_high_lnb_voltage) + err = fe->ops.enable_high_lnb_voltage(fe, (long)parg); + break; + + case FE_SET_FRONTEND_TUNE_MODE: + fepriv->tune_mode_flags = (unsigned long)parg; + err = 0; + break; + /* DEPRECATED dish control ioctls */ + case FE_DISHNETWORK_SEND_LEGACY_CMD: if (fe->ops.dishnetwork_send_legacy_command) { err = fe->ops.dishnetwork_send_legacy_command(fe, @@ -2401,14 +2623,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file, * initialization, so parg is 8 bits and does not * include the initialization or start bit */ - unsigned long swcmd = ((unsigned long) parg) << 1; + unsigned long swcmd = ((unsigned long)parg) << 1; ktime_t nexttime; ktime_t tv[10]; int i; u8 last = 1; + if (dvb_frontend_debug) - dprintk("%s switch command: 0x%04lx\n", - __func__, swcmd); + dprintk("switch command: 0x%04lx\n", + swcmd); nexttime = ktime_get_boottime(); if (dvb_frontend_debug) tv[0] = nexttime; @@ -2420,7 +2643,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, for (i = 0; i < 9; i++) { if (dvb_frontend_debug) - tv[i+1] = ktime_get_boottime(); + tv[i + 1] = ktime_get_boottime(); if ((swcmd & 0x01) != last) { /* set voltage to (last ? 13V : 18V) */ fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); @@ -2431,11 +2654,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file, dvb_frontend_sleep_until(&nexttime, 8000); } if (dvb_frontend_debug) { - dprintk("%s(%d): switch delay (should be 32k followed by all 8k)\n", - __func__, fe->dvb->num); + dprintk("(adapter %d): switch delay (should be 32k followed by all 8k)\n", + fe->dvb->num); for (i = 1; i < 10; i++) pr_info("%d: %d\n", i, - (int) ktime_us_delta(tv[i], tv[i-1])); + (int)ktime_us_delta(tv[i], tv[i - 1])); } err = 0; fepriv->state = FESTATE_DISEQC; @@ -2443,16 +2666,46 @@ static int dvb_frontend_ioctl_legacy(struct file *file, } break; - case FE_DISEQC_RECV_SLAVE_REPLY: - if (fe->ops.diseqc_recv_slave_reply) - err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); + /* DEPRECATED statistics ioctls */ + + case FE_READ_BER: + if (fe->ops.read_ber) { + if (fepriv->thread) + err = fe->ops.read_ber(fe, parg); + else + err = -EAGAIN; + } break; - case FE_ENABLE_HIGH_LNB_VOLTAGE: - if (fe->ops.enable_high_lnb_voltage) - err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); + case FE_READ_SIGNAL_STRENGTH: + if (fe->ops.read_signal_strength) { + if (fepriv->thread) + err = fe->ops.read_signal_strength(fe, parg); + else + err = -EAGAIN; + } break; + case FE_READ_SNR: + if (fe->ops.read_snr) { + if (fepriv->thread) + err = fe->ops.read_snr(fe, parg); + else + err = -EAGAIN; + } + break; + + case FE_READ_UNCORRECTED_BLOCKS: + if (fe->ops.read_ucblocks) { + if (fepriv->thread) + err = fe->ops.read_ucblocks(fe, parg); + else + err = -EAGAIN; + } + break; + + /* DEPRECATED DVBv3 ioctls */ + case FE_SET_FRONTEND: err = dvbv3_set_delivery_system(fe); if (err) @@ -2463,33 +2716,34 @@ static int dvb_frontend_ioctl_legacy(struct file *file, break; err = dtv_set_frontend(fe); break; + case FE_GET_EVENT: - err = dvb_frontend_get_event (fe, parg, file->f_flags); + err = dvb_frontend_get_event(fe, parg, file->f_flags); break; - case FE_GET_FRONTEND: { - struct dtv_frontend_properties getp = fe->dtv_property_cache; + case FE_GET_FRONTEND: + err = dvb_get_frontend(fe, parg); + break; - /* - * Let's use our own copy of property cache, in order to - * avoid mangling with DTV zigzag logic, as drivers might - * return crap, if they don't check if the data is available - * before updating the properties cache. - */ - err = dtv_get_frontend(fe, &getp, parg); - break; - } - case FE_SET_FRONTEND_TUNE_MODE: - fepriv->tune_mode_flags = (unsigned long) parg; - err = 0; - break; - } + default: + return -ENOTSUPP; + } /* switch */ return err; } +#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 unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) + +static __poll_t dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; @@ -2497,10 +2751,10 @@ static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struc dev_dbg_ratelimited(fe->dvb->device, "%s:\n", __func__); - poll_wait (file, &fepriv->events.wait_queue, wait); + poll_wait(file, &fepriv->events.wait_queue, wait); if (fepriv->events.eventw != fepriv->events.eventr) - return (POLLIN | POLLRDNORM | POLLPRI); + return (EPOLLIN | EPOLLRDNORM | EPOLLPRI); return 0; } @@ -2518,9 +2772,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) return -ENODEV; if (adapter->mfe_shared) { - mutex_lock (&adapter->mfe_lock); + mutex_lock(&adapter->mfe_lock); - if (adapter->mfe_dvbdev == NULL) + if (!adapter->mfe_dvbdev) adapter->mfe_dvbdev = dvbdev; else if (adapter->mfe_dvbdev != dvbdev) { @@ -2532,23 +2786,23 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) *mfepriv = mfe->frontend_priv; int mferetry = (dvb_mfe_wait_time << 1); - mutex_unlock (&adapter->mfe_lock); + mutex_unlock(&adapter->mfe_lock); while (mferetry-- && (mfedev->users != -1 || - mfepriv->thread != NULL)) { - if(msleep_interruptible(500)) { - if(signal_pending(current)) + mfepriv->thread)) { + if (msleep_interruptible(500)) { + if (signal_pending(current)) return -EINTR; } } - mutex_lock (&adapter->mfe_lock); - if(adapter->mfe_dvbdev != dvbdev) { + mutex_lock(&adapter->mfe_lock); + if (adapter->mfe_dvbdev != dvbdev) { mfedev = adapter->mfe_dvbdev; mfe = mfedev->priv; mfepriv = mfe->frontend_priv; if (mfedev->users != -1 || - mfepriv->thread != NULL) { - mutex_unlock (&adapter->mfe_lock); + mfepriv->thread) { + mutex_unlock(&adapter->mfe_lock); return -EBUSY; } adapter->mfe_dvbdev = dvbdev; @@ -2569,7 +2823,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) fepriv->reinitialise = 1; } - if ((ret = dvb_generic_open (inode, file)) < 0) + if ((ret = dvb_generic_open(inode, file)) < 0) goto err1; if ((file->f_flags & O_ACCMODE) != O_RDONLY) { @@ -2579,6 +2833,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) fepriv->voltage = -1; #ifdef CONFIG_MEDIA_CONTROLLER_DVB + mutex_lock(&fe->dvb->mdev_lock); if (fe->dvb->mdev) { mutex_lock(&fe->dvb->mdev->graph_mutex); if (fe->dvb->mdev->enable_source) @@ -2587,13 +2842,15 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) &fepriv->pipe); mutex_unlock(&fe->dvb->mdev->graph_mutex); if (ret) { + mutex_unlock(&fe->dvb->mdev_lock); dev_err(fe->dvb->device, "Tuner is busy. Error %d\n", ret); goto err2; } } + mutex_unlock(&fe->dvb->mdev_lock); #endif - ret = dvb_frontend_start (fe); + ret = dvb_frontend_start(fe); if (ret) goto err3; @@ -2604,17 +2861,19 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) dvb_frontend_get(fe); if (adapter->mfe_shared) - mutex_unlock (&adapter->mfe_lock); + mutex_unlock(&adapter->mfe_lock); return ret; err3: #ifdef CONFIG_MEDIA_CONTROLLER_DVB + mutex_lock(&fe->dvb->mdev_lock); if (fe->dvb->mdev) { mutex_lock(&fe->dvb->mdev->graph_mutex); if (fe->dvb->mdev->disable_source) fe->dvb->mdev->disable_source(dvbdev->entity); mutex_unlock(&fe->dvb->mdev->graph_mutex); } + mutex_unlock(&fe->dvb->mdev_lock); err2: #endif dvb_generic_release(inode, file); @@ -2623,7 +2882,7 @@ err1: fe->ops.ts_bus_ctrl(fe, 0); err0: if (adapter->mfe_shared) - mutex_unlock (&adapter->mfe_lock); + mutex_unlock(&adapter->mfe_lock); return ret; } @@ -2641,17 +2900,19 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) mb(); } - ret = dvb_generic_release (inode, file); + ret = dvb_generic_release(inode, file); if (dvbdev->users == -1) { wake_up(&fepriv->wait_queue); #ifdef CONFIG_MEDIA_CONTROLLER_DVB + mutex_lock(&fe->dvb->mdev_lock); if (fe->dvb->mdev) { mutex_lock(&fe->dvb->mdev->graph_mutex); if (fe->dvb->mdev->disable_source) fe->dvb->mdev->disable_source(dvbdev->entity); mutex_unlock(&fe->dvb->mdev->graph_mutex); } + mutex_unlock(&fe->dvb->mdev_lock); #endif if (fe->exit != DVB_FE_NO_EXIT) wake_up(&dvbdev->wait_queue); @@ -2666,7 +2927,10 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) static const struct file_operations dvb_frontend_fops = { .owner = THIS_MODULE, - .unlocked_ioctl = dvb_generic_ioctl, + .unlocked_ioctl = dvb_frontend_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = dvb_frontend_compat_ioctl, +#endif .poll = dvb_frontend_poll, .open = dvb_frontend_open, .release = dvb_frontend_release, @@ -2678,7 +2942,7 @@ int dvb_frontend_suspend(struct dvb_frontend *fe) int ret = 0; dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, - fe->id); + fe->id); if (fe->ops.tuner_ops.suspend) ret = fe->ops.tuner_ops.suspend(fe); @@ -2698,7 +2962,7 @@ int dvb_frontend_resume(struct dvb_frontend *fe) int ret = 0; dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, - fe->id); + fe->id); fe->exit = DVB_FE_DEVICE_RESUME; if (fe->ops.init) @@ -2722,19 +2986,18 @@ int dvb_frontend_resume(struct dvb_frontend *fe) } EXPORT_SYMBOL(dvb_frontend_resume); -int dvb_register_frontend(struct dvb_adapter* dvb, - struct dvb_frontend* fe) +int dvb_register_frontend(struct dvb_adapter *dvb, + struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv; const struct dvb_device dvbdev_template = { .users = ~0, .writers = 1, - .readers = (~0)-1, + .readers = (~0) - 1, .fops = &dvb_frontend_fops, #if defined(CONFIG_MEDIA_CONTROLLER_DVB) .name = fe->ops.info.name, #endif - .kernel_ioctl = dvb_frontend_ioctl }; dev_dbg(dvb->device, "%s:\n", __func__); @@ -2743,7 +3006,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, return -ERESTARTSYS; fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL); - if (fe->frontend_priv == NULL) { + if (!fe->frontend_priv) { mutex_unlock(&frontend_mutex); return -ENOMEM; } @@ -2759,18 +3022,18 @@ int dvb_register_frontend(struct dvb_adapter* dvb, dvb_frontend_get(fe); sema_init(&fepriv->sem, 1); - init_waitqueue_head (&fepriv->wait_queue); - init_waitqueue_head (&fepriv->events.wait_queue); + init_waitqueue_head(&fepriv->wait_queue); + init_waitqueue_head(&fepriv->events.wait_queue); mutex_init(&fepriv->events.mtx); fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; - dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, - fe, DVB_DEVICE_FRONTEND, 0); - dev_info(fe->dvb->device, - "DVB: registering adapter %i frontend %i (%s)...\n", - fe->dvb->num, fepriv->dvbdev->id, fe->ops.info.name); + "DVB: registering adapter %i frontend %i (%s)...\n", + fe->dvb->num, fe->id, fe->ops.info.name); + + dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template, + fe, DVB_DEVICE_FRONTEND, 0); /* * Initialize the cache to the proper values according with the @@ -2785,9 +3048,10 @@ int dvb_register_frontend(struct dvb_adapter* dvb, } EXPORT_SYMBOL(dvb_register_frontend); -int dvb_unregister_frontend(struct dvb_frontend* fe) +int dvb_unregister_frontend(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; + dev_dbg(fe->dvb->device, "%s:\n", __func__); mutex_lock(&frontend_mutex); @@ -2812,12 +3076,11 @@ static void dvb_frontend_invoke_release(struct dvb_frontend *fe, } } -void dvb_frontend_detach(struct dvb_frontend* fe) +void dvb_frontend_detach(struct dvb_frontend *fe) { dvb_frontend_invoke_release(fe, fe->ops.release_sec); dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release); dvb_frontend_invoke_release(fe, fe->ops.analog_ops.release); - dvb_frontend_invoke_release(fe, fe->ops.detach); dvb_frontend_put(fe); } EXPORT_SYMBOL(dvb_frontend_detach); diff --git a/dvb-core/dvb_math.c b/dvb-core/dvb_math.c index a2e1810..dc90564 100644 --- a/dvb-core/dvb_math.c +++ b/dvb-core/dvb_math.c @@ -19,7 +19,7 @@ #include #include #include -#include "dvb_math.h" +#include static const unsigned short logtable[256] = { 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, diff --git a/dvb-core/dvb_net.c b/dvb-core/dvb_net.c index dbbc2a3..70a2a5b 100644 --- a/dvb-core/dvb_net.c +++ b/dvb-core/dvb_net.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * dvb_net.c * @@ -13,18 +14,6 @@ * and Wolfram Stering * * 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 , * Paris Lodron University of Salzburg. @@ -69,8 +58,8 @@ #include #include -#include "dvb_demux.h" -#include "dvb_net.h" +#include +#include 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; @@ -1010,12 +992,12 @@ static void dvb_net_sec(struct net_device *dev, } static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_section_filter *filter) + const u8 *buffer2, size_t buffer2_len, + 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; diff --git a/dvb-core/dvb_ringbuffer.c b/dvb-core/dvb_ringbuffer.c index 6406e6e..42f39af 100644 --- a/dvb-core/dvb_ringbuffer.c +++ b/dvb-core/dvb_ringbuffer.c @@ -34,7 +34,7 @@ #include #endif -#include "dvb_ringbuffer.h" +#include #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 diff --git a/dvb-core/dvbdev.c b/dvb-core/dvbdev.c index 6d63578..d4bf829 100644 --- a/dvb-core/dvbdev.c +++ b/dvb-core/dvbdev.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,7 @@ #include #include #include -#include "dvbdev.h" +#include #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,8 +346,10 @@ 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) { @@ -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); diff --git a/frontends/Makefile b/frontends/Makefile index 49b8417..a6de4a5 100644 --- a/frontends/Makefile +++ b/frontends/Makefile @@ -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 diff --git a/frontends/cxd2099.h b/frontends/cxd2099.h index f4b29b1..1235d5e 100644 --- a/frontends/cxd2099.h +++ b/frontends/cxd2099.h @@ -25,7 +25,7 @@ #ifndef _CXD2099_H_ #define _CXD2099_H_ -#include +#include struct cxd2099_cfg { u32 bitrate; diff --git a/frontends/cxd2843.c b/frontends/cxd2843.c index c0d10f2..d6f0646 100644 --- a/frontends/cxd2843.c +++ b/frontends/cxd2843.c @@ -35,8 +35,8 @@ #include #include -#include "dvb_frontend.h" -#include "dvb_math.h" +#include +#include #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 | diff --git a/frontends/drxk_hard.c b/frontends/drxk_hard.c index 3ef782e..456e382 100644 --- a/frontends/drxk_hard.c +++ b/frontends/drxk_hard.c @@ -31,7 +31,7 @@ #include #include -#include "dvb_frontend.h" +#include #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 | diff --git a/frontends/lnbh25.c b/frontends/lnbh25.c index 9e904c5..823ac15 100644 --- a/frontends/lnbh25.c +++ b/frontends/lnbh25.c @@ -30,7 +30,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "lnbh25.h" struct lnbh25 { diff --git a/frontends/lnbp21.c b/frontends/lnbp21.c index f70b1cb..61e4269 100644 --- a/frontends/lnbp21.c +++ b/frontends/lnbp21.c @@ -32,7 +32,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "lnbp21.h" #include "lnbh24.h" diff --git a/frontends/mxl5xx.c b/frontends/mxl5xx.c index 078f33d..6f7308b 100644 --- a/frontends/mxl5xx.c +++ b/frontends/mxl5xx.c @@ -41,7 +41,7 @@ #include #include -#include "dvb_frontend.h" +#include #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 | diff --git a/frontends/stv0367dd.c b/frontends/stv0367dd.c index 3f4f247..d127545 100644 --- a/frontends/stv0367dd.c +++ b/frontends/stv0367dd.c @@ -31,7 +31,7 @@ #include #include -#include "dvb_frontend.h" +#include #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 */ diff --git a/frontends/stv090x.c b/frontends/stv090x.c index f818902..6ec0ecf 100644 --- a/frontends/stv090x.c +++ b/frontends/stv090x.c @@ -28,7 +28,7 @@ #include #include -#include "dvb_frontend.h" +#include #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 | diff --git a/frontends/stv090x_priv.h b/frontends/stv090x_priv.h index 8c1953f..97a9efe 100644 --- a/frontends/stv090x_priv.h +++ b/frontends/stv090x_priv.h @@ -22,7 +22,7 @@ #ifndef __STV090x_PRIV_H #define __STV090x_PRIV_H -#include "dvb_frontend.h" +#include #define FE_ERROR 0 #define FE_NOTICE 1 diff --git a/frontends/stv0910.c b/frontends/stv0910.c index ab1b4c4..b289ef7 100644 --- a/frontends/stv0910.c +++ b/frontends/stv0910.c @@ -31,7 +31,7 @@ #include #include -#include "dvb_frontend.h" +#include #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 | diff --git a/frontends/stv6110x.c b/frontends/stv6110x.c index 66eba38..4469f4a 100644 --- a/frontends/stv6110x.c +++ b/frontends/stv6110x.c @@ -26,7 +26,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "stv6110x_reg.h" #include "stv6110x.h" @@ -345,10 +345,10 @@ 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, + .name = "STV6110(A) Silicon Tuner", + .frequency_min_hz = 950000000, + .frequency_max_hz = 2150000000, + .frequency_step_hz = 0, }, .release = stv6110x_release }; diff --git a/frontends/stv6111.c b/frontends/stv6111.c index 0689df5..3d10d8a 100644 --- a/frontends/stv6111.c +++ b/frontends/stv6111.c @@ -31,7 +31,7 @@ #include #include -#include "dvb_frontend.h" +#include 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, diff --git a/frontends/tda18212dd.c b/frontends/tda18212dd.c index 5629e5e..cf43a22 100644 --- a/frontends/tda18212dd.c +++ b/frontends/tda18212dd.c @@ -32,7 +32,7 @@ #include #include -#include "dvb_frontend.h" +#include #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, diff --git a/frontends/tda18271c2dd.c b/frontends/tda18271c2dd.c index 4ea9a71..39fd090 100644 --- a/frontends/tda18271c2dd.c +++ b/frontends/tda18271c2dd.c @@ -32,7 +32,7 @@ #include #include -#include "dvb_frontend.h" +#include 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, diff --git a/dvb-core/demux.h b/include/linux/media/demux.h similarity index 97% rename from dvb-core/demux.h rename to include/linux/media/demux.h index c4df6ce..bf00a5a 100644 --- a/dvb-core/demux.h +++ b/include/linux/media/demux.h @@ -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 diff --git a/include/linux/media/dmxdev.h b/include/linux/media/dmxdev.h new file mode 100644 index 0000000..729e36e --- /dev/null +++ b/include/linux/media/dmxdev.h @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#ifdef CONFIG_DVB_MMAP +#include +#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_ */ diff --git a/dvb-core/dvb_ca_en50221.h b/include/linux/media/dvb_ca_en50221.h similarity index 99% rename from dvb-core/dvb_ca_en50221.h rename to include/linux/media/dvb_ca_en50221.h index 367687d..a1c014b 100644 --- a/dvb-core/dvb_ca_en50221.h +++ b/include/linux/media/dvb_ca_en50221.h @@ -20,7 +20,7 @@ #include #include -#include "dvbdev.h" +#include #define DVB_CA_EN50221_POLL_CAM_PRESENT 1 #define DVB_CA_EN50221_POLL_CAM_CHANGED 2 diff --git a/include/linux/media/dvb_demux.h b/include/linux/media/dvb_demux.h new file mode 100644 index 0000000..3b6aeca --- /dev/null +++ b/include/linux/media/dvb_demux.h @@ -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 +#include +#include +#include + +#include + +/** + * 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_ */ diff --git a/dvb-core/dvb_filter.h b/include/linux/media/dvb_filter.h similarity index 100% rename from dvb-core/dvb_filter.h rename to include/linux/media/dvb_filter.h diff --git a/dvb-core/dvb_frontend.h b/include/linux/media/dvb_frontend.h similarity index 83% rename from dvb-core/dvb_frontend.h rename to include/linux/media/dvb_frontend.h index b5c48b5..2132da2 100644 --- a/dvb-core/dvb_frontend.h +++ b/include/linux/media/dvb_frontend.h @@ -46,10 +46,11 @@ #include #include #include +#include #include -#include "dvbdev.h" +#include /* * 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; @@ -104,10 +106,10 @@ struct dvb_tuner_info { * struct analog_parameters - Parameters to tune into an analog/radio channel * * @frequency: Frequency used by analog TV tuner (either in 62.5 kHz step, - * for TV, or 62.5 Hz for radio) + * for TV, or 62.5 Hz for radio) * @mode: Tuner mode, as defined on enum v4l2_tuner_type * @audmode: Audio mode as defined for the rxsubchans field at videodev2.h, - * e. g. V4L2_TUNER_MODE_* + * e. g. V4L2_TUNER_MODE_* * @std: TV standard bitmap as defined at videodev2.h, e. g. V4L2_STD_* * * Hybrid tuners should be supported by both V4L2 and DVB APIs. This @@ -145,10 +147,10 @@ struct analog_parameters { * These devices have AUTO recovery capabilities from LOCK failure */ 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. + * 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;, + * rate. Newer drivers should provide such info via + * 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]; }; @@ -506,7 +529,7 @@ struct dvb_fe_events { * @fec_inner: Forward error correction inner Code Rate * @transmission_mode: Transmission Mode * @bandwidth_hz: Bandwidth, in Hz. A zero value means that userspace - * wants to autodetect. + * wants to autodetect. * @guard_interval: Guard Interval * @hierarchy: Hierarchy * @symbol_rate: Symbol Rate @@ -529,8 +552,8 @@ struct dvb_fe_events { * @layer.interleaving: per layer interleaving. * @stream_id: If different than zero, enable substream filtering, if * hardware supports (DVB-S2 and DVB-T2). - * @scrambling_sequence_index: Carries the index of the DVB-S2 physical layer - * scrambling sequence. + * @scrambling_sequence_index: Carries the index of the DVB-S2 physical layer + * scrambling sequence. * @atscmh_fic_ver: Version number of the FIC (Fast Information Channel) * signaling data (only ATSC-M/H) * @atscmh_parade_id: Parade identification number (only ATSC-M/H) @@ -554,7 +577,7 @@ struct dvb_fe_events { * @lna: Power ON/OFF/AUTO the Linear Now-noise Amplifier (LNA) * @strength: DVBv5 API statistics: Signal Strength * @cnr: DVBv5 API statistics: Signal to Noise ratio of the - * (main) carrier + * (main) carrier * @pre_bit_error: DVBv5 API statistics: pre-Viterbi bit error count * @pre_bit_count: DVBv5 API statistics: pre-Viterbi bit count * @post_bit_error: DVBv5 API statistics: post-Viterbi bit error count @@ -575,15 +598,15 @@ struct dtv_frontend_properties { enum fe_sec_voltage voltage; enum fe_sec_tone_mode sectone; - enum fe_spectral_inversion inversion; - enum fe_code_rate fec_inner; + enum fe_spectral_inversion inversion; + enum fe_code_rate fec_inner; enum fe_transmit_mode transmission_mode; u32 bandwidth_hz; /* 0 = AUTO */ enum fe_guard_interval guard_interval; - enum fe_hierarchy hierarchy; + enum fe_hierarchy hierarchy; u32 symbol_rate; - enum fe_code_rate code_rate_HP; - enum fe_code_rate code_rate_LP; + enum fe_code_rate code_rate_HP; + enum fe_code_rate code_rate_LP; enum fe_pilot pilot; enum fe_rolloff rolloff; @@ -610,7 +633,7 @@ struct dtv_frontend_properties { u32 stream_id; /* Physical Layer Scrambling specifics */ - u32 scrambling_sequence_index; + u32 scrambling_sequence_index; /* ATSC-MH specifics */ u8 atscmh_fic_ver; @@ -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 diff --git a/dvb-core/dvb_math.h b/include/linux/media/dvb_math.h similarity index 100% rename from dvb-core/dvb_math.h rename to include/linux/media/dvb_math.h diff --git a/dvb-core/dvb_net.h b/include/linux/media/dvb_net.h similarity index 56% rename from dvb-core/dvb_net.h rename to include/linux/media/dvb_net.h index e9b18aa..5e31d37 100644 --- a/dvb-core/dvb_net.h +++ b/include/linux/media/dvb_net.h @@ -24,12 +24,28 @@ #include #include -#include "dvbdev.h" +#include #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 diff --git a/dvb-core/dvb_ringbuffer.h b/include/linux/media/dvb_ringbuffer.h similarity index 100% rename from dvb-core/dvb_ringbuffer.h rename to include/linux/media/dvb_ringbuffer.h diff --git a/include/linux/media/dvb_vb2.h b/include/linux/media/dvb_vb2.h new file mode 100644 index 0000000..8cb8845 --- /dev/null +++ b/include/linux/media/dvb_vb2.h @@ -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 +#include +#include +#include +#include +#include + +/** + * 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 */ diff --git a/dvb-core/dvbdev.h b/include/linux/media/dvbdev.h similarity index 59% rename from dvb-core/dvbdev.h rename to include/linux/media/dvbdev.h index f4dc90e..c4005df 100644 --- a/dvb-core/dvbdev.h +++ b/include/linux/media/dvbdev.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; @@ -176,7 +200,7 @@ struct dvb_device { * @module: initialized with THIS_MODULE at the caller * @device: pointer to struct device that corresponds to the device driver * @adapter_nums: Array with a list of the numbers for @dvb_register_adapter; - * to select among them. Typically, initialized with: + * to select among them. Typically, initialized with: * DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums) */ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, @@ -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); /** @@ -244,9 +266,9 @@ void dvb_unregister_device(struct dvb_device *dvbdev); #ifdef CONFIG_MEDIA_CONTROLLER_DVB /** * dvb_create_media_graph - Creates media graph for the Digital TV part of the - * device. + * device. * - * @adap: pointer to struct dvb_adapter + * @adap: pointer to &struct dvb_adapter * @create_rf_connector: if true, it creates the RF connector too * * 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, - unsigned int cmd, unsigned long arg); +/** + * 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); -/* we don't mess with video_usercopy() any more, -we simply define out own dvb_usercopy(), which will hopefully become -generic_usercopy() someday... */ +/** + * 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); + +/** + * 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_ */