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

Merge branch 'internal'

This commit is contained in:
rjkm 2020-11-10 15:49:53 +01:00
commit 0e13bdcb08
85 changed files with 4848 additions and 2594 deletions

View File

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

View File

@ -32,16 +32,18 @@
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/types.h> #include <linux/types.h>
#include <errno.h>
#include "flash.h" #include "flash.h"
#include "flash.c"
void get_id(int ddb, struct ddb_id *ddbid) { void get_ddid(int ddb, struct ddb_id *ddbid) {
uint8_t id[4]; uint8_t id[4];
if (ioctl(ddb, IOCTL_DDB_ID, ddbid)>=0) if (ioctl(ddb, IOCTL_DDB_ID, ddbid)>=0)
return; return;
memset(ddbid, 0, sizeof(*ddbid)); memset(ddbid, 0, sizeof(*ddbid));
flashread(ddb, id, 0, 4); flashread(ddb, linknr, id, 0, 4);
printf("%02x %02x %02x %02x\n", printf("%02x %02x %02x %02x\n",
id[0], id[1], id[2], id[3]); id[0], id[1], id[2], id[3]);
ddbid->subvendor=(id[0] << 8) | id[1]; ddbid->subvendor=(id[0] << 8) | id[1];
@ -70,6 +72,7 @@ int sure()
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
char ddbname[80]; char ddbname[80];
char *flashname;
int type = 0; int type = 0;
struct ddb_id ddbid; struct ddb_id ddbid;
uint8_t *buffer; uint8_t *buffer;
@ -145,10 +148,10 @@ int main(int argc, char **argv)
printf("Could not open device\n"); printf("Could not open device\n");
return -1; return -1;
} }
Flash = flashdetect(ddb, &SectorSize, &FlashSize); Flash = flashdetect(ddb, &SectorSize, &FlashSize, &flashname);
get_id(ddb, &ddbid); get_ddid(ddb, &ddbid);
#if 1 #if 0
printf("%04x %04x %04x %04x %08x %08x\n", printf("%04x %04x %04x %04x %08x %08x\n",
ddbid.vendor, ddbid.device, ddbid.vendor, ddbid.device,
ddbid.subvendor, ddbid.subdevice, ddbid.subvendor, ddbid.subdevice,
@ -156,7 +159,7 @@ int main(int argc, char **argv)
#endif #endif
if (dump) { if (dump) {
flashdump(ddb, dump, 128); flashdump(ddb, linknr, dump, 128);
return 0; return 0;
} }
@ -202,85 +205,13 @@ int main(int argc, char **argv)
} else { } else {
int fh, i; int fh, i;
int fsize; int fsize;
char *name;
if (!fname) if (!fname)
switch (ddbid.device) { fname = devid2fname(ddbid.device, &name);
case 0x0002: if (name)
fname="DVBBridgeV1A_DVBBridgeV1A.bit"; printf("Card: %s\n", name);
printf("Octopus 35\n");
break;
case 0x0003:
fname="DVBBridgeV1B_DVBBridgeV1B.fpga";
printf("Octopus\n");
break;
case 0x0005:
fname="DVBBridgeV2A_DD01_0005_STD.fpga";
printf("Octopus Classic\n");
break;
case 0x0006:
fname="DVBBridgeV2A_DD01_0006_STD.fpga";
printf("CineS2 V7\n");
break;
case 0x0007:
fname="DVBBridgeV2A_DD01_0007_MXL.fpga";
printf("Octopus 4/8\n");
break;
case 0x0008:
fname="DVBBridgeV2A_DD01_0008_CXD.fpga";
printf("Octopus 4/8\n");
break;
case 0x0009:
fname="DVBBridgeV2A_DD01_0009_SX8.fpga";
printf("Octopus MAXSX8\n");
break;
case 0x000a:
fname="DVBBridgeV2A_DD01_000A_M4.fpga";
printf("Octopus MAXM4\n");
break;
case 0x0011:
fname="DVBBridgeV2B_DD01_0011.fpga";
printf("Octopus CI\n");
break;
case 0x0012:
fname="DVBBridgeV2B_DD01_0012_STD.fpga";
printf("Octopus CI\n");
break;
case 0x0013:
fname="DVBBridgeV2B_DD01_0013_PRO.fpga";
printf("Octopus PRO\n");
break;
case 0x0020:
fname="DVBBridgeV2C_DD01_0020.fpga";
printf("Octopus GT Mini\n");
break;
case 0x0201:
fname="DVBModulatorV1B_DVBModulatorV1B.bit";
printf("Modulator\n");
break;
case 0x0203:
fname="DVBModulatorV1B_DD01_0203.fpga";
printf("Modulator Test\n");
break;
case 0x0210:
fname="DVBModulatorV2A_DD01_0210.fpga";
printf("Modulator V2\n");
break;
case 0x0220:
fname="SDRModulatorV1A_DD01_0220.fpga";
printf("SDRModulator ATV\n");
break;
case 0x0221:
fname="SDRModulatorV1A_DD01_0221_IQ.fpga";
printf("SDRModulator IQ\n");
break;
case 0x0222:
fname="SDRModulatorV1A_DD01_0222_DVBT.fpga";
printf("SDRModulator DVBT\n");
break;
default:
printf("UNKNOWN\n");
break;
}
fh = open(fname, O_RDONLY); fh = open(fname, O_RDONLY);
if (fh < 0 ) { if (fh < 0 ) {
printf("File %s not found \n", fname); printf("File %s not found \n", fname);

View File

@ -6,10 +6,10 @@ install: all
install -m 0755 octokey $(DESTDIR)/usr/bin install -m 0755 octokey $(DESTDIR)/usr/bin
install -m 0755 ddflash $(DESTDIR)/usr/bin install -m 0755 ddflash $(DESTDIR)/usr/bin
ddflash: ddflash.c ddflash: ddflash.c flash.h flash.c
$(CC) -o ddflash ddflash.c $(CC) -o ddflash ddflash.c
ddtest: ddtest.c ddtest: ddtest.c flash.h flash.c
$(CC) -o ddtest ddtest.c $(CC) -o ddtest ddtest.c
octonet: octonet.c octonet: octonet.c

View File

@ -36,6 +36,7 @@
#include <linux/types.h> #include <linux/types.h>
#include "flash.h" #include "flash.h"
#include "flash.c"
static int reboot(uint32_t off) static int reboot(uint32_t off)
{ {
@ -55,540 +56,6 @@ static int reboot(uint32_t off)
return 0; return 0;
} }
struct ddflash {
int fd;
struct ddb_id id;
uint32_t version;
uint32_t flash_type;
uint32_t sector_size;
uint32_t size;
uint32_t bufsize;
uint32_t block_erase;
uint8_t *buffer;
};
int flashwrite_pagemode(struct ddflash *ddf, int dev, uint32_t FlashOffset,
uint8_t LockBits, uint32_t fw_off)
{
int err = 0;
uint8_t cmd[260];
int i, j;
uint32_t flen, blen;
blen = flen = lseek(dev, 0, SEEK_END) - fw_off;
if (blen % 0xff)
blen = (blen + 0xff) & 0xffffff00;
printf("blen = %u, flen = %u\n", blen, flen);
do {
cmd[0] = 0x50; // EWSR
err = flashio(ddf->fd, cmd, 1, NULL, 0);
if (err < 0)
break;
cmd[0] = 0x01; // WRSR
cmd[1] = 0x00; // BPx = 0, Unlock all blocks
err = flashio(ddf->fd, cmd, 2, NULL, 0);
if (err < 0)
break;
for (i = 0; i < flen; i += 4096) {
if ((i & 0xFFFF) == 0)
printf(" Erase %08x\n", FlashOffset + i);
cmd[0] = 0x06; // WREN
err = flashio(ddf->fd, cmd, 1, NULL, 0);
if (err < 0)
break;
cmd[0] = 0x20; // Sector erase ( 4Kb)
cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF );
cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF );
cmd[3] = 0x00;
err = flashio(ddf->fd, cmd, 4, NULL, 0);
if (err < 0)
break;
while (1) {
cmd[0] = 0x05; // RDRS
err = flashio(ddf->fd, cmd, 1, &cmd[0], 1);
if (err < 0)
break;
if ((cmd[0] & 0x01) == 0)
break;
}
if (err < 0)
break;
}
if (err < 0)
break;
for (j = blen - 256; j >= 0; j -= 256 ) {
uint32_t len = 256;
ssize_t rlen;
if (lseek(dev, j + fw_off, SEEK_SET) < 0) {
printf("seek error\n");
return -1;
}
if (flen - j < 256) {
len = flen - j;
memset(ddf->buffer, 0xff, 256);
}
rlen = read(dev, ddf->buffer, len);
if (rlen < 0 || rlen != len) {
printf("file read error %d,%d at %u\n", rlen, errno, j);
return -1;
}
printf ("write %u bytes at %08x\n", len, j);
if ((j & 0xFFFF) == 0)
printf(" Programm %08x\n", FlashOffset + j);
cmd[0] = 0x06; // WREN
err = flashio(ddf->fd, cmd, 1, NULL, 0);
if (err < 0)
break;
cmd[0] = 0x02; // PP
cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF );
cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF );
cmd[3] = 0x00;
memcpy(&cmd[4], ddf->buffer, 256);
err = flashio(ddf->fd, cmd, 260, NULL, 0);
if (err < 0)
break;
while(1) {
cmd[0] = 0x05; // RDRS
err = flashio(ddf->fd, cmd,1, &cmd[0], 1);
if (err < 0)
break;
if ((cmd[0] & 0x01) == 0)
break;
}
if (err < 0)
break;
}
if (err < 0)
break;
cmd[0] = 0x50; // EWSR
err = flashio(ddf->fd, cmd, 1, NULL, 0);
if (err < 0)
break;
cmd[0] = 0x01; // WRSR
cmd[1] = LockBits; // BPx = 0, Lock all blocks
err = flashio(ddf->fd, cmd, 2, NULL, 0);
} while(0);
return err;
}
static int flashwrite_SSTI(struct ddflash *ddf, int fs, uint32_t FlashOffset, uint32_t maxlen, uint32_t fw_off)
{
int err = 0;
uint8_t cmd[6];
int i, j;
uint32_t flen, blen;
blen = flen = lseek(fs, 0, SEEK_END) - fw_off;
if (blen % 0xfff)
blen = (blen + 0xfff) & 0xfffff000;
printf("blen = %u, flen = %u\n", blen, flen);
do {
#if 1
cmd[0] = 0x50; // EWSR
err = flashio(ddf->fd, cmd, 1, NULL, 0);
if (err < 0)
break;
cmd[0] = 0x01; // WRSR
cmd[1] = 0x00; // BPx = 0, Unlock all blocks
err = flashio(ddf->fd, cmd, 2, NULL, 0);
if (err < 0 )
break;
for (i = 0; i < flen; i += 4096) {
if ((i & 0xFFFF) == 0 )
printf("Erase %08x\n", FlashOffset + i);
cmd[0] = 0x06; // WREN
err = flashio(ddf->fd, cmd, 1, NULL, 0);
if (err < 0 )
break;
cmd[0] = 0x20; // Sector erase ( 4Kb)
cmd[1] = (((FlashOffset + i ) >> 16) & 0xFF);
cmd[2] = (((FlashOffset + i ) >> 8) & 0xFF);
cmd[3] = 0x00;
err = flashio(ddf->fd,cmd,4,NULL,0);
if (err < 0 )
break;
while(1) {
cmd[0] = 0x05; // RDRS
err = flashio(ddf->fd,cmd,1,&cmd[0],1);
if (err < 0 ) break;
if ((cmd[0] & 0x01) == 0 ) break;
}
if (err < 0 ) break;
}
if (err < 0 )
break;
#endif
for (j = blen - 4096; j >= 0; j -= 4096 ) {
uint32_t len = 4096;
ssize_t rlen;
if (lseek(fs, j + fw_off, SEEK_SET) < 0) {
printf("seek error\n");
return -1;
}
if (flen - j < 4096) {
len = flen - j;
memset(ddf->buffer, 0xff, 4096);
}
rlen = read(fs, ddf->buffer, len);
if (rlen < 0 || rlen != len) {
printf("file read error %d,%d at %u\n", rlen, errno, j);
return -1;
}
printf ("write %u bytes at %08x\n", len, j);
if ((j & 0xFFFF) == 0 )
printf(" Program %08x\n",FlashOffset + j);
#if 1
for (i = 0; i < 4096; i += 2) {
if (i == 0) {
cmd[0] = 0x06; // WREN
err = flashio(ddf->fd, cmd, 1, NULL, 0);
if (err < 0 )
break;
cmd[0] = 0xAD; // AAI
cmd[1] = ((( FlashOffset + j ) >> 16) & 0xFF );
cmd[2] = ((( FlashOffset + j ) >> 8) & 0xFF );
cmd[3] = 0x00;
cmd[4] = ddf->buffer[i];
cmd[5] = ddf->buffer[i + 1];
err = flashio(ddf->fd,cmd,6,NULL,0);
} else {
cmd[0] = 0xAD; // AAI
cmd[1] = ddf->buffer[i];
cmd[2] = ddf->buffer[i + 1];
err = flashio(ddf->fd,cmd,3,NULL,0);
}
if (err < 0 )
break;
while(1) {
cmd[0] = 0x05; // RDRS
err = flashio(ddf->fd,cmd,1,&cmd[0],1);
if (err < 0 ) break;
if ((cmd[0] & 0x01) == 0 ) break;
}
if (err < 0 )
break;
}
if (err < 0)
break;
cmd[0] = 0x04; // WDIS
err = flashio(ddf->fd, cmd, 1, NULL, 0);
if (err < 0 )
break;
#endif
}
if (err < 0 ) break;
cmd[0] = 0x50; // EWSR
err = flashio(ddf->fd,cmd,1,NULL,0);
if (err < 0 ) break;
cmd[0] = 0x01; // WRSR
cmd[1] = 0x1C; // BPx = 0, Lock all blocks
err = flashio(ddf->fd,cmd,2,NULL,0);
} while(0);
return err;
}
static int flashwrite(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, uint32_t fw_off)
{
switch (ddf->flash_type) {
case SSTI_SST25VF016B:
case SSTI_SST25VF032B:
return flashwrite_SSTI(ddf, fs, addr, maxlen, fw_off);
case SSTI_SST25VF064C:
return flashwrite_pagemode(ddf, fs, addr, 0x3c, fw_off);
case SPANSION_S25FL116K:
case SPANSION_S25FL132K:
case SPANSION_S25FL164K:
return flashwrite_pagemode(ddf, fs, addr, 0x1c, fw_off);
}
return -1;
}
static int flashcmp(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, uint32_t fw_off)
{
off_t off;
uint32_t len;
int i, j, rlen;
uint8_t buf[256], buf2[256];
int bl = sizeof(buf);
off = lseek(fs, 0, SEEK_END);
if (off < 0)
return -1;
len = off - fw_off;
lseek(fs, fw_off, SEEK_SET);
if (len > maxlen) {
printf("file too big\n");
return -1;
}
printf("flash file len %u, compare to %08x in flash\n", len, addr);
for (j = 0; j < len; j += bl, addr += bl) {
if (len - j < bl)
bl = len - j;
flashread(ddf->fd, buf, addr, bl);
rlen = read(fs, buf2, bl);
if (rlen < 0 || rlen != bl) {
printf("read error\n");
return -1;
}
if (memcmp(buf, buf2, bl)) {
printf("flash differs at %08x (offset %u)\n", addr, j);
dump(buf, 32);
dump(buf2, 32);
return addr;
}
}
printf("flash same as file\n");
return -2;
}
static int flash_detect(struct ddflash *ddf)
{
uint8_t cmd = 0x9F;
uint8_t id[3];
int r = flashio(ddf->fd, &cmd, 1, id, 3);
if (r < 0)
return r;
if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x41) {
ddf->flash_type = SSTI_SST25VF016B;
printf("Flash: SSTI SST25VF016B 16 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x200000;
} else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4A) {
ddf->flash_type = SSTI_SST25VF032B;
printf("Flash: SSTI SST25VF032B 32 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x400000;
} else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4B) {
ddf->flash_type = SSTI_SST25VF064C;
printf("Flash: SSTI SST25VF064C 64 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x800000;
} else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x15) {
ddf->flash_type = SPANSION_S25FL116K;
printf("Flash: SPANSION S25FL116K 16 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x200000;
} else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x16) {
ddf->flash_type = SPANSION_S25FL132K;
printf("Flash: SPANSION S25FL132K 32 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x400000;
} else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x17) {
ddf->flash_type = SPANSION_S25FL164K;
printf("Flash: SPANSION S25FL164K 64 MBit\n");
ddf->sector_size = 4096;
ddf->size = 0x800000;
} else if (id[0] == 0x1F && id[1] == 0x28) {
ddf->flash_type = ATMEL_AT45DB642D;
printf("Flash: Atmel AT45DB642D 64 MBit\n");
ddf->sector_size = 1024;
ddf->size = 0x800000;
} else {
printf("Unknown Flash Flash ID = %02x %02x %02x\n", id[0], id[1], id[2]);
return -1;
}
if (ddf->sector_size) {
ddf->buffer = malloc(ddf->sector_size);
//printf("allocated buffer %08x@%08x\n", ddf->sector_size, (uint32_t) ddf->buffer);
if (!ddf->buffer)
return -1;
}
return 0;
}
static int get_id(struct ddflash *ddf) {
uint8_t id[4];
if (ioctl(ddf->fd, IOCTL_DDB_ID, &ddf->id) < 0)
return -1;
#if 1
printf("%04x %04x %04x %04x %08x %08x\n",
ddf->id.vendor, ddf->id.device,
ddf->id.subvendor, ddf->id.subdevice,
ddf->id.hw, ddf->id.regmap);
#endif
return 0;
}
static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off)
{
int fd, fsize, ret = 0;
off_t off;
uint32_t p, i;
uint8_t *buf;
uint8_t hdr[256];
unsigned int devid, version, length;
unsigned int cid[8];
int cids = 0;
uint32_t maxlen = 1024 * 1024;
fd = open(fn, O_RDONLY);
if (fd < 0) {
printf("%s: not found\n", fn);
return -1;
}
off = lseek(fd, 0, SEEK_END);
if (off < 0)
return -1;
fsize = off;
if (fsize > maxlen) {
close(fd);
return -1;
}
lseek(fd, 0, SEEK_SET);
buf = malloc(fsize);
if (!buf)
return -1;
read(fd, buf, fsize);
close(fd);
for (p = 0; p < fsize && buf[p]; p++) {
char *key = &buf[p], *val = NULL;
for (; p < fsize && buf[p] != 0x0a; p++) {
if (buf[p] == ':') {
buf[p] = 0;
val = &buf[p + 1];
}
}
if (val == NULL || p == fsize)
break;
buf[p] = 0;
//printf("%-20s:%s\n", key, val);
if (!strcasecmp(key, "Devid")) {
sscanf(val, "%x", &devid);
} else if (!strcasecmp(key, "Compat")) {
cids = sscanf(val, "%x,%x,%x,%x,%x,%x,%x,%x",
&cid[0], &cid[1], &cid[2], &cid[3],
&cid[4], &cid[5], &cid[6], &cid[7]);
if (cids < 1)
break;
for (i = 0; i < cids; i++)
if (cid[i] == ddf->id.device)
break;
if (i == cids) {
printf("%s: no compatible id\n", fn);
ret = -2; /* no compatible ID */
goto out;
}
} else if (!strcasecmp(key, "Version")) {
if (strchr(val,'.')) {
int major = 0, minor = 0;
sscanf(val,"%d.%d",&major,&minor);
version = (major << 16) + minor;
} else
sscanf(val, "%x", &version);
} else if (!strcasecmp(key, "Length")) {
sscanf(val, "%u", &length);
}
}
p++;
*fw_off = p;
printf("devid = %04x\n", devid);
printf("version = %08x %08x\n", version, ddf->id.hw);
printf("length = %u\n", length);
printf("fsize = %u, p = %u, f-p = %u\n", fsize, p, fsize - p);
if (devid == ddf->id.device) {
if (version <= (ddf->id.hw & 0xffffff)) {
printf("%s: old version\n", fn);
ret = -3; /* same id but no newer version */
}
} else
ret = 1;
out:
free(buf);
printf("check_fw = %d\n", ret);
return ret;
}
static int update_image(struct ddflash *ddf, char *fn,
uint32_t adr, uint32_t len,
int has_header, int no_change)
{
int fs, res = 0;
uint32_t fw_off = 0;
printf("Check %s\n", fn);
if (has_header) {
int ck;
ck = check_fw(ddf, fn, &fw_off);
if (ck < 0)
return ck;
if (ck == 1 && no_change)
return 0;
}
fs = open(fn, O_RDONLY);
if (fs < 0 ) {
printf("File %s not found \n", fn);
return -1;
}
res = flashcmp(ddf, fs, adr, len, fw_off);
if (res == -2) {
printf("%s: same as flash\n", fn);
}
if (res < 0)
goto out;
res = flashwrite(ddf, fs, adr, len, fw_off);
if (res == 0) {
res = flashcmp(ddf, fs, adr, len, fw_off);
if (res == -2) {
res = 1;
}
}
out:
close(fs);
return res;
}
static int fexists(char *fn)
{
struct stat b;
return (!stat(fn, &b));
}
static int update_flash(struct ddflash *ddf) static int update_flash(struct ddflash *ddf)
{ {
@ -730,6 +197,7 @@ int main(int argc, char **argv)
return -1; return -1;
} }
} }
ddf.link = 0;
flash = flash_detect(&ddf); flash = flash_detect(&ddf);
if (flash < 0) if (flash < 0)
return -1; return -1;

View File

@ -10,8 +10,10 @@
#include <string.h> #include <string.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <linux/types.h> #include <linux/types.h>
#include <errno.h>
#include "flash.h" #include "flash.h"
#include "flash.c"
typedef int (*COMMAND_FUNCTION)(int dev, int argc, char* argv[], uint32_t Flags); typedef int (*COMMAND_FUNCTION)(int dev, int argc, char* argv[], uint32_t Flags);
@ -51,7 +53,7 @@ int ReadFlash(int ddb, int argc, char *argv[], uint32_t Flags)
} }
Buffer = malloc(Len); Buffer = malloc(Len);
if (flashread(ddb, Buffer, Start, Len) < 0) { if (flashread(ddb, linknr, Buffer, Start, Len) < 0) {
printf("flashread error\n"); printf("flashread error\n");
free(Buffer); free(Buffer);
return 0; return 0;
@ -81,7 +83,7 @@ int ReadSave(int ddb, int argc, char *argv[], uint32_t Flags)
Len = strtoul(argv[1],NULL,16); Len = strtoul(argv[1],NULL,16);
Buffer = malloc(Len); Buffer = malloc(Len);
if (flashread(ddb, Buffer, Start, Len) < 0) { if (flashread(ddb, linknr, Buffer, Start, Len) < 0) {
printf("flashread error\n"); printf("flashread error\n");
free(Buffer); free(Buffer);
return 0; return 0;
@ -108,12 +110,12 @@ int FlashChipEraseAtmel(int dev)
Cmd[1] = ( (( i ) >> 16) & 0xFF ); Cmd[1] = ( (( i ) >> 16) & 0xFF );
Cmd[2] = ( (( i ) >> 8) & 0xFF ); Cmd[2] = ( (( i ) >> 8) & 0xFF );
Cmd[3] = 0x00; Cmd[3] = 0x00;
err = flashio(dev,Cmd,4,NULL,0); err = flashio(dev,linknr, Cmd,4,NULL,0);
if( err < 0 ) if( err < 0 )
break; break;
while (1) { while (1) {
Cmd[0] = 0xD7; // Read Status register Cmd[0] = 0xD7; // Read Status register
err = flashio(dev,Cmd,1,&Cmd[0],1); err = flashio(dev,linknr, Cmd,1,&Cmd[0],1);
if( err < 0 ) break; if( err < 0 ) break;
if( (Cmd[0] & 0x80) == 0x80 ) break; if( (Cmd[0] & 0x80) == 0x80 ) break;
} }
@ -131,25 +133,25 @@ int FlashChipEraseSSTI(int dev)
do { do {
Cmd[0] = 0x50; // EWSR Cmd[0] = 0x50; // EWSR
err = flashio(dev,Cmd,1,NULL,0); err = flashio(dev, linknr, Cmd,1,NULL,0);
if( err < 0 ) break; if( err < 0 ) break;
Cmd[0] = 0x01; // WRSR Cmd[0] = 0x01; // WRSR
Cmd[1] = 0x00; // BPx = 0, Unlock all blocks Cmd[1] = 0x00; // BPx = 0, Unlock all blocks
err = flashio(dev,Cmd,2,NULL,0); err = flashio(dev, linknr, Cmd,2,NULL,0);
if( err < 0 ) break; if( err < 0 ) break;
Cmd[0] = 0x06; // WREN Cmd[0] = 0x06; // WREN
err = flashio(dev,Cmd,1,NULL,0); err = flashio(dev, linknr, Cmd,1,NULL,0);
if( err < 0 ) break; if( err < 0 ) break;
Cmd[0] = 0x60; // CHIP Erase Cmd[0] = 0x60; // CHIP Erase
err = flashio(dev,Cmd,1,NULL,0); err = flashio(dev, linknr, Cmd,1,NULL,0);
if( err < 0 ) break; if( err < 0 ) break;
while(1) { while(1) {
Cmd[0] = 0x05; // RDRS Cmd[0] = 0x05; // RDRS
err = flashio(dev,Cmd,1,&Cmd[0],1); err = flashio(dev, linknr, Cmd,1,&Cmd[0],1);
if( err < 0 ) break; if( err < 0 ) break;
if( (Cmd[0] & 0x01) == 0 ) break; if( (Cmd[0] & 0x01) == 0 ) break;
} }
@ -157,12 +159,12 @@ int FlashChipEraseSSTI(int dev)
break; break;
Cmd[0] = 0x50; // EWSR Cmd[0] = 0x50; // EWSR
err = flashio(dev,Cmd,1,NULL,0); err = flashio(dev, linknr, Cmd,1,NULL,0);
if( err < 0 ) break; if( err < 0 ) break;
Cmd[0] = 0x01; // WRSR Cmd[0] = 0x01; // WRSR
Cmd[1] = 0x1C; // BPx = 0, Lock all blocks Cmd[1] = 0x1C; // BPx = 0, Lock all blocks
err = flashio(dev,Cmd,2,NULL,0); err = flashio(dev, linknr, Cmd,2,NULL,0);
} }
while(0); while(0);
@ -332,7 +334,7 @@ int flashioc(int dev,int argc, char* argv[],uint32_t Flags)
Buffer[i] = (uint8_t) tmp; Buffer[i] = (uint8_t) tmp;
} }
if( flashio(dev,Buffer,WriteLen,Buffer,ReadLen) < 0 ) if( flashio(dev, linknr, Buffer,WriteLen,Buffer,ReadLen) < 0 )
{ {
return 0; return 0;
} }
@ -384,8 +386,8 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
int BufferSize = 0; int BufferSize = 0;
int BlockErase = 0; int BlockErase = 0;
uint32_t FlashOffset = 0x10000; uint32_t FlashOffset = 0x10000;
int SectorSize = 0; uint32_t SectorSize = 0;
int FlashSize = 0; uint32_t FlashSize = 0;
int ValidateFPGAType = 1; int ValidateFPGAType = 1;
int Flash; int Flash;
uint32_t Id1, Id2; uint32_t Id1, Id2;
@ -533,7 +535,7 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags)
printf("out of memory\n"); printf("out of memory\n");
return 0; return 0;
} }
if (flashread(dev, CmpBuffer, FlashOffset, 0x10000)<0) { if (flashread(dev, linknr, CmpBuffer, FlashOffset, 0x10000)<0) {
printf("Ioctl returns error\n"); printf("Ioctl returns error\n");
free(Buffer); free(Buffer);
free(CmpBuffer); free(CmpBuffer);
@ -660,7 +662,7 @@ int FlashVerify(int dev,int argc, char* argv[],uint32_t Flags)
// Place our own header // Place our own header
} }
#endif #endif
if (flashread(dev, Buffer2, FlashOffset, BufferSize)<0) { if (flashread(dev, linknr, Buffer2, FlashOffset, BufferSize)<0) {
printf("Ioctl returns error\n"); printf("Ioctl returns error\n");
free(Buffer); free(Buffer);
free(Buffer2); free(Buffer2);
@ -1112,7 +1114,7 @@ char *GetSerNbr(int dev)
int i; int i;
memset(Buffer,0,sizeof(Buffer)); memset(Buffer,0,sizeof(Buffer));
if (flashread(dev, Buffer, Start, sizeof(Buffer) - 1)) if (flashread(dev, linknr, Buffer, Start, sizeof(Buffer) - 1))
{ {
printf("Ioctl returns error\n"); printf("Ioctl returns error\n");
return NULL; return NULL;
@ -1289,7 +1291,7 @@ static int read_sfpd(int dev, uint8_t adr, uint8_t *val)
uint8_t cmd[5] = { 0x5a, 0, 0, adr, 0 }; uint8_t cmd[5] = { 0x5a, 0, 0, adr, 0 };
int r; int r;
r = flashio(dev, cmd, 5, val, 1); r = flashio(dev, linknr, cmd, 5, val, 1);
if (r < 0) if (r < 0)
return r; return r;
return 0; return 0;
@ -1301,7 +1303,7 @@ static int read_sst_id(int dev, uint8_t *id)
uint8_t buf[9]; uint8_t buf[9];
int r; int r;
r = flashio(dev, cmd, 2, buf, 9); r = flashio(dev, linknr, cmd, 2, buf, 9);
if (r < 0) if (r < 0)
return r; return r;
memcpy(id, buf + 1, 8); memcpy(id, buf + 1, 8);
@ -1313,7 +1315,7 @@ static int read_winbd(int dev, uint8_t *val)
uint8_t cmd[5] = { 0x4b, 0, 0, 0, 0 }; uint8_t cmd[5] = { 0x4b, 0, 0, 0, 0 };
int r; int r;
r = flashio(dev, cmd, 5, val, 8); r = flashio(dev, linknr, cmd, 5, val, 8);
if (r < 0) if (r < 0)
return r; return r;
return 0; return 0;

269
apps/octonet/ddupdate.c Normal file
View File

@ -0,0 +1,269 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h>
#include <getopt.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <sys/ioctl.h>
#include <linux/types.h>
#include "flash.h"
#include "flash.c"
static int verbose = 0;
static int yesno()
{
char c;
printf("\n\nNew firmware available\nReally flash now? y/n\n");
fflush(0);
c = getchar();
if (c!='y') {
printf("\nFlashing aborted.\n\n");
return 0;
}
printf("\nStarting to flash\n\n");
return 1;
}
static int update_flash(struct ddflash *ddf)
{
char *fname, *default_fname;
int res, stat = 0;
char *name = 0, *dname;
switch (ddf->id.device) {
case 0x300:
case 0x301:
case 0x302:
case 0x307:
if ((res = update_image(ddf, "/boot/bs.img", 0x4000, 0x1000, 0, 0)) == 1)
stat |= 4;
if ((res = update_image(ddf, "/boot/uboot.img", 0xb0000, 0xb0000, 0, 0)) == 1)
stat |= 2;
if (fexists("/config/gtl.enabled")) {
if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x10000, 0xa0000, 1, 0)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x10000, 0xa0000, 1, 0)) == 1)
stat |= 1;
} else if (fexists("/config/gtl.disabled")) {
if ((res = update_image(ddf, "/config/fpga.img", 0x10000, 0xa0000, 1, 0)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 0)) == 1)
stat |= 1;
} else {
if (ddf->id.device == 0x0307) {
if (res == -1)
if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
} else {
if ((res = update_image(ddf, "/config/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1)
stat |= 1;
}
}
#if 1
if ( (stat&1) && (ddf->id.hw & 0xffffff) <= 0x010001) {
if (ddf->id.device == 0x0307) {
if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x160000, 0x80000, 1, 0)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x160000, 0x80000, 1, 0)) == 1)
stat |= 1;
} else {
if ((res = update_image(ddf, "/config/fpga.img", 0x160000, 0x80000, 1, 0)) == 1)
stat |= 1;
if (res == -1)
if ((res = update_image(ddf, "/boot/fpga.img", 0x160000, 0x80000, 1, 0)) == 1)
stat |= 1;
}
}
#endif
break;
case 0x320:
//fname="/boot/DVBNetV1A_DD01_0300.bit";
fname="/boot/fpga.img";
if ((res = update_image(ddf, fname, 0x10000, 0x100000, 1, 0)) == 1)
stat |= 1;
return stat;
break;
case 0x322:
//fname="/boot/DVBNetV1A_DD01_0300.bit";
fname="/boot/fpga.img";
if ((res = update_image(ddf, fname, 0x10000, 0x100000, 1, 0)) == 1)
stat |= 1;
return stat;
break;
default:
fname = ddf->fname;
default_fname = devid2fname(ddf->id.device, &name);
if (!fname)
fname = default_fname;
if (name)
printf("Card: %s\n", name);
if (ddf->flash_name)
printf("Flash: %s\n", ddf->flash_name);
printf("Version:%08x\n", ddf->id.hw);
//printf("REGMAPa: %08x\n", ddf->id.regmap);
if ((res = update_image(ddf, fname, 0x10000, 0x100000, 1, 0)) == 1)
stat |= 1;
return stat;
}
return stat;
}
static int update_link(struct ddflash *ddf)
{
int ret;
ret = flash_detect(ddf);
if (ret < 0)
return ret;
ret = update_flash(ddf);
if (ddf->buffer)
free(ddf->buffer);
return ret;
}
static int update_card(int ddbnum, char *fname)
{
struct ddflash ddf;
char ddbname[80];
struct ddb_id ddbid;
int ddb, ret, link, links;
sprintf(ddbname, "/dev/ddbridge/card%d", ddbnum);
ddb = open(ddbname, O_RDWR);
if (ddb < 0)
return -3;
ddf.fd = ddb;
ddf.link = 0;
ddf.fname = fname;
links = 1;
for (link = 0; link < links; link++) {
ddf.link = link;
if (verbose >= 2)
printf("Get id card %u link %u\n", ddbnum, link);
ret = get_id(&ddf);
if (ret < 0)
goto out;
if (!link) {
switch (ddf.id.device) {
case 0x20:
links = 4;
break;
case 0x300:
case 0x301:
case 0x307:
links = 2;
break;
default:
break;
}
}
//printf("%08x %08x\n", ddf.id.device, ddf.id.subdevice);
if (ddf.id.device) {
printf("\n\nUpdate card %s link %u:\n", ddbname, link);
ret = update_link(&ddf);
//if (ret < 0)
// break;
}
}
out:
close(ddb);
return ret;
}
static int usage()
{
printf("ddupdate [OPTION]\n\n"
"-n N\n only update card N (default with N=0)\n\n"
"-a \n update all cards\n\n"
"-b file\n fpga image file override (ignored if -a is used)\n\n"
"-v \n more verbose (up to -v -v -v)\n\n"
);
}
int main(int argc, char **argv)
{
int ddbnum = -1, all = 0, i, force = 0;
char *fname = 0;
while (1) {
int option_index = 0;
int c;
static struct option long_options[] = {
{"help", no_argument , NULL, 'h'},
{0, 0, 0, 0}
};
c = getopt_long(argc, argv,
"n:havfb:",
long_options, &option_index);
if (c==-1)
break;
switch (c) {
case 'b':
fname = optarg;
break;
case 'n':
ddbnum = strtol(optarg, NULL, 0);
break;
case 'a':
all = 1;
break;
case 'v':
verbose++;
break;
case 'h':
usage();
break;
default:
break;
}
}
if (optind < argc) {
printf("Warning: unused arguments\n");
}
if (!all && (ddbnum < 0)) {
printf("Select card number or all cards\n\n");
usage();
return -1;
}
if (!all)
return update_card(ddbnum, fname);
for (i = 0; i < 100; i++) {
int ret = update_card(i, 0);
if (ret == -3) /* could not open, no more cards! */
break;
if (ret < 0)
return i; /* fatal error */
if (verbose >= 1)
printf("card %d up to date\n", i);
}
return 0;
}

File diff suppressed because it is too large Load Diff

View File

@ -62,4 +62,45 @@ struct ddb_i2c_msg {
#define IOCTL_DDB_READ_I2C _IOWR(DDB_MAGIC, 0x0a, struct ddb_i2c_msg) #define IOCTL_DDB_READ_I2C _IOWR(DDB_MAGIC, 0x0a, struct ddb_i2c_msg)
#define IOCTL_DDB_WRITE_I2C _IOR(DDB_MAGIC, 0x0b, struct ddb_i2c_msg) #define IOCTL_DDB_WRITE_I2C _IOR(DDB_MAGIC, 0x0b, struct ddb_i2c_msg)
#include "flash.c" enum {
UNKNOWN_FLASH = 0,
ATMEL_AT45DB642D = 1,
SSTI_SST25VF016B = 2,
SSTI_SST25VF032B = 3,
SSTI_SST25VF064C = 4,
SPANSION_S25FL116K = 5,
SPANSION_S25FL132K = 6,
SPANSION_S25FL164K = 7,
WINBOND_W25Q16JV = 8,
WINBOND_W25Q32JV = 9,
WINBOND_W25Q64JV = 10,
WINBOND_W25Q128JV = 11,
};
struct flash_info {
uint8_t id[3];
uint32_t type;
uint32_t ssize;
uint32_t fsize;
char *name;
};
struct ddflash {
int fd;
uint32_t link;
char *fname;
struct ddb_id id;
uint32_t version;
char *flash_name;
uint32_t flash_type;
uint32_t sector_size;
uint32_t size;
uint32_t bufsize;
uint32_t block_erase;
uint8_t *buffer;
};

103
apps/tscheck.c Normal file
View File

@ -0,0 +1,103 @@
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/dvb/dmx.h>
#include <linux/dvb/frontend.h>
#include <linux/dvb/video.h>
char line_start[16] = "";
char line_end[16] = "\r";
uint32_t cc_errors = 0;
uint32_t packets = 0;
uint32_t payload_packets = 0;
uint32_t packet_errors = 0;
uint8_t cc[8192] = { 0 };
void proc_ts(int i, uint8_t *buf)
{
uint16_t pid= 0x1fff& ((buf[1] << 8) | buf[2]);
uint8_t ccin = buf[3] & 0x1f;
if( buf[0] == 0x47 && (buf[1] & 0x80) == 0) {
if( pid != 8191 ) {
if (ccin & 0x10) {
if( cc[pid] != 0 ) {
// TODO: 1 repetition allowed
if ((((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) )
cc_errors += 1;
}
cc[pid] = ccin;
}
payload_packets += 1;
}
} else
packet_errors += 1;
if( (packets & 0x3FFF ) == 0) {
printf("%s Packets: %12u non null %12u, errors: %12u, CC errors: %12u%s",
line_start, packets, payload_packets, packet_errors, cc_errors, line_end);
fflush(stdout);
}
packets += 1;
}
#define TSBUFSIZE (100*188)
void citest(char* n)
{
uint8_t *buf;
uint8_t id;
int i, nts;
int len;
int ts=open(n, O_RDONLY);
buf=(uint8_t *)malloc(TSBUFSIZE);
while(1) {
len=read(ts, buf, TSBUFSIZE);
if (len<0) {
continue;
}
if (buf[0]!=0x47) {
read(ts, buf, 1);
continue;
}
if (len%188) { /* should not happen */
printf("blah\n");
continue;
}
nts=len/188;
for (i=0; i<nts; i++)
proc_ts(i, buf+i*188);
}
}
int main(int argc, char* argv[])
{
if( argc < 2 )
{
printf("tscheck <file>|<device> [<display line>]\n");
exit(0);
}
if( argc > 2 )
{
int line = atoi(argv[2]);
if( line >= 0 && line < 64 )
{
snprintf(line_start,sizeof(line_start)-1,"\0337\033[%d;0H",line);
strncpy(line_end,"\0338",sizeof(line_end)-1);
}
}
citest(argv[1]);
}

View File

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

View File

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

View File

@ -329,7 +329,7 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate)
case DDB_CI_EXTERNAL_XO2_B: case DDB_CI_EXTERNAL_XO2_B:
ci_xo2_attach(port); ci_xo2_attach(port);
break; break;
case DDB_CI_INTERNAL: case DDB_CI_INTERNAL:
ci_attach(port); ci_attach(port);
break; break;

View File

@ -24,7 +24,7 @@
#include "ddbridge.h" #include "ddbridge.h"
#include "ddbridge-i2c.h" #include "ddbridge-i2c.h"
#include "ddbridge-io.h" #include "ddbridge-io.h"
#include "dvb_net.h" #include <media/dvb_net.h>
struct workqueue_struct *ddb_wq; struct workqueue_struct *ddb_wq;
@ -56,6 +56,10 @@ static int xo2_speed = 2;
module_param(xo2_speed, int, 0444); module_param(xo2_speed, int, 0444);
MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards"); MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards");
static int raw_stream;
module_param(raw_stream, int, 0444);
MODULE_PARM_DESC(raw_stream, "send data as raw stream to DVB layer");
#ifdef __arm__ #ifdef __arm__
static int alt_dma = 1; static int alt_dma = 1;
#else #else
@ -99,6 +103,7 @@ struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr,
irq->data = data; irq->data = data;
return irq; return irq;
} }
EXPORT_SYMBOL(ddb_irq_set);
static void ddb_set_dma_table(struct ddb_io *io) static void ddb_set_dma_table(struct ddb_io *io)
{ {
@ -328,6 +333,7 @@ static int ddb_buffers_alloc(struct ddb *dev)
if (dma_alloc(dev->pdev, if (dma_alloc(dev->pdev,
port->input[0]->dma, 0) < 0) port->input[0]->dma, 0) < 0)
return -1; return -1;
/* fallthrough */
case DDB_PORT_MOD: case DDB_PORT_MOD:
if (port->output->dma) if (port->output->dma)
if (dma_alloc(dev->pdev, if (dma_alloc(dev->pdev,
@ -481,9 +487,8 @@ static void ddb_output_start_unlocked(struct ddb_output *output)
} }
if (output->port->class != DDB_PORT_MOD) if (output->port->class != DDB_PORT_MOD)
ddbwritel(dev, con | 1, TS_CONTROL(output)); ddbwritel(dev, con | 1, TS_CONTROL(output));
if (output->dma) { if (output->dma)
output->dma->running = 1; output->dma->running = 1;
}
} }
static void ddb_output_start(struct ddb_output *output) static void ddb_output_start(struct ddb_output *output)
@ -531,6 +536,14 @@ static void ddb_input_stop_unlocked(struct ddb_input *input)
if (input->dma) { if (input->dma) {
ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma));
input->dma->running = 0; input->dma->running = 0;
if (input->dma->stall_count)
dev_warn(input->port->dev->dev,
"DMA stalled %u times!\n",
input->dma->stall_count);
if (input->dma->packet_loss)
dev_warn(input->port->dev->dev,
"%u packets lost due to low DMA performance!\n",
input->dma->packet_loss);
} }
} }
@ -553,6 +566,8 @@ static void ddb_input_start_unlocked(struct ddb_input *input)
input->dma->cbuf = 0; input->dma->cbuf = 0;
input->dma->coff = 0; input->dma->coff = 0;
input->dma->stat = 0; input->dma->stat = 0;
input->dma->stall_count = 0;
input->dma->packet_loss = 0;
ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma));
} }
ddbwritel(dev, 0, TS_CONTROL(input)); ddbwritel(dev, 0, TS_CONTROL(input));
@ -568,13 +583,16 @@ static void ddb_input_start_unlocked(struct ddb_input *input)
} }
if (dev->link[0].info->type == DDB_OCTONET) if (dev->link[0].info->type == DDB_OCTONET)
ddbwritel(dev, 0x01, TS_CONTROL(input)); ddbwritel(dev, 0x01, TS_CONTROL(input));
else else {
ddbwritel(dev, 0x09, TS_CONTROL(input)); if (raw_stream)
ddbwritel(dev, 0x01 | ((raw_stream & 3) << 8), TS_CONTROL(input));
else
ddbwritel(dev, 0x01 | input->con, TS_CONTROL(input));
}
if (input->port->type == DDB_TUNER_DUMMY) if (input->port->type == DDB_TUNER_DUMMY)
ddbwritel(dev, 0x000fff01, TS_CONTROL2(input)); ddbwritel(dev, 0x000fff01, TS_CONTROL2(input));
if (input->dma) { if (input->dma)
input->dma->running = 1; input->dma->running = 1;
}
} }
static void ddb_input_start(struct ddb_input *input) static void ddb_input_start(struct ddb_input *input)
@ -651,7 +669,7 @@ static u32 ddb_output_free(struct ddb_output *output)
if (output->dma->cbuf != idx) { if (output->dma->cbuf != idx) {
if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && if ((((output->dma->cbuf + 1) % output->dma->num) == idx) &&
(output->dma->size - output->dma->coff <= 2*188)) (output->dma->size - output->dma->coff <= 2 * 188))
return 0; return 0;
return 188; return 188;
} }
@ -661,25 +679,6 @@ static u32 ddb_output_free(struct ddb_output *output)
return 0; return 0;
} }
#if 0
static u32 ddb_dma_free(struct ddb_dma *dma)
{
u32 idx, off, stat = dma->stat;
s32 p1, p2, diff;
idx = (stat >> 11) & 0x1f;
off = (stat & 0x7ff) << 7;
p1 = idx * dma->size + off;
p2 = dma->cbuf * dma->size + dma->coff;
diff = p1 - p2;
if (diff <= 0)
diff += dma->num * dma->size;
return diff;
}
#endif
static ssize_t ddb_output_write(struct ddb_output *output, static ssize_t ddb_output_write(struct ddb_output *output,
const __user u8 *buf, size_t count) const __user u8 *buf, size_t count)
{ {
@ -735,79 +734,6 @@ static ssize_t ddb_output_write(struct ddb_output *output,
return count - left; return count - left;
} }
#if 0
static u32 ddb_input_free_bytes(struct ddb_input *input)
{
struct ddb *dev = input->port->dev;
u32 idx, off, stat = input->dma->stat;
u32 ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(input->dma));
idx = (stat >> 11) & 0x1f;
off = (stat & 0x7ff) << 7;
if (ctrl & 4)
return 0;
if (input->dma->cbuf != idx)
return 1;
return 0;
}
static s32 ddb_output_used_bufs(struct ddb_output *output)
{
u32 idx, off, stat, ctrl;
s32 diff;
spin_lock_irq(&output->dma->lock);
stat = output->dma->stat;
ctrl = output->dma->ctrl;
spin_unlock_irq(&output->dma->lock);
idx = (stat >> 11) & 0x1f;
off = (stat & 0x7ff) << 7;
if (ctrl & 4)
return 0;
diff = output->dma->cbuf - idx;
if (diff == 0 && off < output->dma->coff)
return 0;
if (diff <= 0)
diff += output->dma->num;
return diff;
}
static s32 ddb_input_free_bufs(struct ddb_input *input)
{
u32 idx, off, stat, ctrl;
s32 free;
spin_lock_irq(&input->dma->lock);
ctrl = input->dma->ctrl;
stat = input->dma->stat;
spin_unlock_irq(&input->dma->lock);
if (ctrl & 4)
return 0;
idx = (stat >> 11) & 0x1f;
off = (stat & 0x7ff) << 7;
free = input->dma->cbuf - idx;
if (free == 0 && off < input->dma->coff)
return 0;
if (free <= 0)
free += input->dma->num;
return free - 1;
}
static u32 ddb_output_ok(struct ddb_output *output)
{
struct ddb_input *input = output->port->input[0];
s32 diff;
diff = ddb_input_free_bufs(input) - ddb_output_used_bufs(output);
if (diff > 0)
return 1;
return 0;
}
#endif
static u32 ddb_input_avail(struct ddb_input *input) static u32 ddb_input_avail(struct ddb_input *input)
{ {
struct ddb *dev = input->port->dev; struct ddb *dev = input->port->dev;
@ -1107,20 +1033,20 @@ static struct dvb_frontend_ops dummy_ops = {
.delsys = { SYS_DVBC_ANNEX_A, SYS_DVBS, SYS_DVBS2 }, .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBS, SYS_DVBS2 },
.info = { .info = {
.name = "DUMMY DVB-C/C2 DVB-T/T2", .name = "DUMMY DVB-C/C2 DVB-T/T2",
.frequency_stepsize = 166667, /* DVB-T only */ .frequency_stepsize_hz = 166667, /* DVB-T only */
.frequency_min = 47000000, /* DVB-T: 47125000 */ .frequency_min_hz = 47000000, /* DVB-T: 47125000 */
.frequency_max = 865000000, /* DVB-C: 862000000 */ .frequency_max_hz = 865000000, /* DVB-C: 862000000 */
.symbol_rate_min = 870000, .symbol_rate_min = 870000,
.symbol_rate_max = 11700000, .symbol_rate_max = 11700000,
.caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 |
FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 |
FE_CAN_QAM_AUTO | FE_CAN_QAM_AUTO |
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
FE_CAN_FEC_4_5 | FE_CAN_FEC_4_5 |
FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO |
FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION
}, },
.release = dummy_release, .release = dummy_release,
.read_status = dummy_read_status, .read_status = dummy_read_status,
@ -1466,29 +1392,6 @@ static int tuner_attach_stv6111(struct ddb_input *input, int type)
return 0; return 0;
} }
#if 0
static int start_input(struct ddb_input *input)
{
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
if (!dvb->users)
ddb_input_start_all(input);
return ++dvb->users;
}
static int stop_input(struct ddb_input *input)
{
struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1];
if (--dvb->users)
return dvb->users;
ddb_input_stop_all(input);
return 0;
}
#endif
static int start_feed(struct dvb_demux_feed *dvbdmxfeed) static int start_feed(struct dvb_demux_feed *dvbdmxfeed)
{ {
struct dvb_demux *dvbdmx = dvbdmxfeed->demux; struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
@ -1585,7 +1488,7 @@ static int dvb_register_adapters(struct ddb *dev)
if (adapter_alloc >= 3 || dev->link[0].info->type == DDB_MOD || if (adapter_alloc >= 3 || dev->link[0].info->type == DDB_MOD ||
dev->link[0].info->type == DDB_OCTONET || dev->link[0].info->type == DDB_OCTONET ||
dev->link[0].info->type == DDB_OCTOPRO ) { dev->link[0].info->type == DDB_OCTOPRO) {
port = &dev->port[0]; port = &dev->port[0];
adap = port->dvb[0].adap; adap = port->dvb[0].adap;
ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE,
@ -1792,6 +1695,7 @@ static int dvb_input_attach(struct ddb_input *input)
osc24 = 0; osc24 = 0;
else else
osc24 = 1; osc24 = 1;
/* fallthrough */
case DDB_TUNER_DVBCT2_SONY_P: case DDB_TUNER_DVBCT2_SONY_P:
case DDB_TUNER_DVBC2T2_SONY_P: case DDB_TUNER_DVBC2T2_SONY_P:
case DDB_TUNER_ISDBT_SONY_P: case DDB_TUNER_ISDBT_SONY_P:
@ -1808,6 +1712,7 @@ static int dvb_input_attach(struct ddb_input *input)
break; break;
case DDB_TUNER_DVBC2T2I_SONY: case DDB_TUNER_DVBC2T2I_SONY:
osc24 = 1; osc24 = 1;
/* fallthrough */
case DDB_TUNER_DVBCT2_SONY: case DDB_TUNER_DVBCT2_SONY:
case DDB_TUNER_DVBC2T2_SONY: case DDB_TUNER_DVBC2T2_SONY:
case DDB_TUNER_ISDBT_SONY: case DDB_TUNER_ISDBT_SONY:
@ -2098,16 +2003,6 @@ static void ddb_port_probe(struct ddb_port *port)
port->class = DDB_PORT_MOD; port->class = DDB_PORT_MOD;
return; return;
} }
#if 0
if (link->info->type == DDB_OCTOPRO_HDIN) {
if (port->nr == 0) {
dev->link[l].info->type = DDB_OCTOPUS;
port->name = "HDIN";
port->class = DDB_PORT_LOOP;
}
return;
}
#endif
if (link->info->type == DDB_OCTOPUS_MAX) { if (link->info->type == DDB_OCTOPUS_MAX) {
port->name = "DUAL DVB-S2 MAX"; port->name = "DUAL DVB-S2 MAX";
port->type_name = "MXL5XX"; port->type_name = "MXL5XX";
@ -2265,6 +2160,7 @@ static int ddb_port_attach(struct ddb_port *port)
ret = ddb_ci_attach(port, ci_bitrate); ret = ddb_ci_attach(port, ci_bitrate);
if (ret < 0) if (ret < 0)
break; break;
/* fallthrough */
case DDB_PORT_LOOP: case DDB_PORT_LOOP:
ret = dvb_register_device(port->dvb[0].adap, ret = dvb_register_device(port->dvb[0].adap,
&port->dvb[0].dev, &port->dvb[0].dev,
@ -2387,9 +2283,15 @@ static void input_write_dvb(struct ddb_input *input,
if (alt_dma) if (alt_dma)
dma_sync_single_for_cpu(dev->dev, dma2->pbuf[dma->cbuf], dma_sync_single_for_cpu(dev->dev, dma2->pbuf[dma->cbuf],
dma2->size, DMA_FROM_DEVICE); dma2->size, DMA_FROM_DEVICE);
dvb_dmx_swfilter_packets(&dvb->demux, if (raw_stream || input->con)
dma2->vbuf[dma->cbuf], dvb_dmx_swfilter_raw(&dvb->demux,
dma2->size / 188); dma2->vbuf[dma->cbuf],
dma2->size);
else
dvb_dmx_swfilter_packets(&dvb->demux,
dma2->vbuf[dma->cbuf],
dma2->size / 188);
dma->cbuf = (dma->cbuf + 1) % dma2->num; dma->cbuf = (dma->cbuf + 1) % dma2->num;
if (ack) if (ack)
ddbwritel(dev, (dma->cbuf << 11), ddbwritel(dev, (dma->cbuf << 11),
@ -2420,10 +2322,17 @@ static void input_tasklet(unsigned long data)
dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma));
dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma));
#if 0 {
u32 packet_loss = dma->packet_loss;
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);
dma->packet_loss = packet_loss;
}
if (4 & dma->ctrl) if (4 & dma->ctrl)
dev_err(dev->dev, "Overflow dma %d\n", dma->nr); dma->stall_count++;
#endif
if (input->redi) if (input->redi)
input_write_dvb(input, input->redi); input_write_dvb(input, input->redi);
if (input->redo) if (input->redo)
@ -2432,7 +2341,7 @@ static void input_tasklet(unsigned long data)
spin_unlock_irqrestore(&dma->lock, flags); spin_unlock_irqrestore(&dma->lock, flags);
} }
#if 0 #ifdef OPTIMIZE_TASKLETS
static void input_handler(unsigned long data) static void input_handler(unsigned long data)
{ {
struct ddb_input *input = (struct ddb_input *)data; struct ddb_input *input = (struct ddb_input *)data;
@ -2494,7 +2403,7 @@ unlock_exit:
spin_unlock_irqrestore(&dma->lock, flags); spin_unlock_irqrestore(&dma->lock, flags);
} }
#if 0 #ifdef OPTIMIZE_TASKLETS
static void output_handler(void *data) static void output_handler(void *data)
{ {
struct ddb_output *output = (struct ddb_output *)data; struct ddb_output *output = (struct ddb_output *)data;
@ -2584,10 +2493,6 @@ static void ddb_dma_init(struct ddb_io *io, int nr, int out, int irq_nr)
dma->div = 1; dma->div = 1;
} }
ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma)); ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma));
#if 0
dev_info(io->port->dev->dev, "init link %u, io %u, dma %u, dmaregs %08x bufregs %08x\n",
io->port->lnr, io->nr, nr, dma->regs, dma->bufregs);
#endif
} }
static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr) static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr)
@ -2612,10 +2517,6 @@ static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr)
if (port->lnr) if (port->lnr)
dma_nr += 32 + (port->lnr - 1) * 8; dma_nr += 32 + (port->lnr - 1) * 8;
#if 0
dev_info(dev->dev, "init link %u, input %u, handler %u\n",
port->lnr, nr, dma_nr + base);
#endif
ddb_irq_set(dev, 0, dma_nr + base, &input_handler, input); ddb_irq_set(dev, 0, dma_nr + base, &input_handler, input);
ddb_dma_init(input, dma_nr, 0, dma_nr + base); ddb_dma_init(input, dma_nr, 0, dma_nr + base);
} }
@ -2633,10 +2534,6 @@ static void ddb_output_init(struct ddb_port *port, int nr)
rm = io_regmap(output, 1); rm = io_regmap(output, 1);
output->regs = DDB_LINK_TAG(port->lnr) | output->regs = DDB_LINK_TAG(port->lnr) |
(rm->output->base + rm->output->size * nr); (rm->output->base + rm->output->size * nr);
#if 0
dev_info(dev->dev, "init link %u, output %u, regs %08x\n",
port->lnr, nr, output->regs);
#endif
if (dev->has_dma) { if (dev->has_dma) {
const struct ddb_regmap *rm0 = io_regmap(output, 0); const struct ddb_regmap *rm0 = io_regmap(output, 0);
u32 base = rm0->irq_base_odma; u32 base = rm0->irq_base_odma;
@ -3336,7 +3233,7 @@ static int ddb_release(struct inode *inode, struct file *file)
{ {
struct ddb *dev = file->private_data; struct ddb *dev = file->private_data;
dev->ddb_dev_users--; atomic_inc(&dev->ddb_dev_users);
return 0; return 0;
} }
@ -3344,9 +3241,10 @@ static int ddb_open(struct inode *inode, struct file *file)
{ {
struct ddb *dev = ddbs[iminor(inode)]; struct ddb *dev = ddbs[iminor(inode)];
if (dev->ddb_dev_users) if (!atomic_dec_and_test(&dev->ddb_dev_users)) {
atomic_inc(&dev->ddb_dev_users);
return -EBUSY; return -EBUSY;
dev->ddb_dev_users++; }
file->private_data = dev; file->private_data = dev;
return 0; return 0;
} }
@ -3646,7 +3544,7 @@ static ssize_t temp_show(struct device *device,
l = attr->attr.name[5] - 0x30; l = attr->attr.name[5] - 0x30;
link = &dev->link[l]; link = &dev->link[l];
if (link->info->type == DDB_MOD ) { if (link->info->type == DDB_MOD) {
if (link->info->version >= 2) { if (link->info->version >= 2) {
temp = 0xffff & ddbreadl(dev, TEMPMON2_BOARD); temp = 0xffff & ddbreadl(dev, TEMPMON2_BOARD);
temp = (temp * 1000) >> 8; temp = (temp * 1000) >> 8;
@ -3718,25 +3616,6 @@ static ssize_t ctemp_show(struct device *device,
return sprintf(buf, "%d\n", temp); return sprintf(buf, "%d\n", temp);
} }
#if 0
static ssize_t qam_show(struct device *device,
struct device_attribute *attr, char *buf)
{
struct ddb *dev = dev_get_drvdata(device);
struct i2c_adapter *adap;
u8 tmp[4];
s16 i, q;
adap = &dev->i2c[1].adap;
if (i2c_read_regs16(adap, 0x1f, 0xf480, tmp, 4) < 0)
return sprintf(buf, "read_error\n");
i = (s16)(((u16)tmp[1]) << 14) | (((u16)tmp[0]) << 6);
q = (s16)(((u16)tmp[3]) << 14) | (((u16)tmp[2]) << 6);
return sprintf(buf, "%d %d\n", i, q);
}
#endif
static ssize_t mod_show(struct device *device, static ssize_t mod_show(struct device *device,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
@ -3917,32 +3796,6 @@ static ssize_t redirect_store(struct device *device,
return count; return count;
} }
#if 0
/* A L P I AAAAAALLPPPPPPII */
/* AAAAAAAA LLLLLLLL PPPPPPII */
static ssize_t redirect2_show(struct device *device,
struct device_attribute *attr, char *buf)
{
return 0;
}
static ssize_t redirect2_store(struct device *device,
struct device_attribute *attr,
const char *buf, size_t count)
{
unsigned int i, p;
int res;
if (sscanf(buf, "%x %x\n", &i, &p) != 2)
return -EINVAL;
res = ddb_redirect(i, p);
if (res < 0)
return res;
dev_info(device, "redirect: %02x, %02x\n", i, p);
return count;
}
#endif
static ssize_t gap_show(struct device *device, static ssize_t gap_show(struct device *device,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
@ -4100,9 +3953,6 @@ static struct device_attribute ddb_attrs[] = {
__ATTR_MRO(devid3, devid_show), __ATTR_MRO(devid3, devid_show),
__ATTR_RO(hwid), __ATTR_RO(hwid),
__ATTR_RO(regmap), __ATTR_RO(regmap),
#if 0
__ATTR_RO(qam),
#endif
__ATTR(redirect, 0664, redirect_show, redirect_store), __ATTR(redirect, 0664, redirect_show, redirect_store),
__ATTR_MRO(snr, bsnr_show), __ATTR_MRO(snr, bsnr_show),
__ATTR_RO(bpsnr), __ATTR_RO(bpsnr),
@ -4170,9 +4020,6 @@ static struct device_attribute ddb_attrs_fanspeed[] = {
static struct class ddb_class = { static struct class ddb_class = {
.name = "ddbridge", .name = "ddbridge",
.owner = THIS_MODULE, .owner = THIS_MODULE,
#if 0
.dev_attrs = ddb_attrs,
#endif
.devnode = ddb_devnode, .devnode = ddb_devnode,
}; };
@ -4205,7 +4052,6 @@ static void ddb_device_attrs_del(struct ddb *dev)
if (dev->link[i].info && if (dev->link[i].info &&
dev->link[i].info->temp_num) dev->link[i].info->temp_num)
device_remove_file(dev->ddb_dev, &ddb_attrs_temp[i]); device_remove_file(dev->ddb_dev, &ddb_attrs_temp[i]);
for (i = 0; i < dev->link[0].info->temp_num; i++)
for (i = 0; i < dev->link[0].info->port_num; i++) for (i = 0; i < dev->link[0].info->port_num; i++)
device_remove_file(dev->ddb_dev, &ddb_attrs_mod[i]); device_remove_file(dev->ddb_dev, &ddb_attrs_mod[i]);
for (i = 0; i < dev->link[0].info->fan_num; i++) for (i = 0; i < dev->link[0].info->fan_num; i++)
@ -4274,6 +4120,7 @@ static int ddb_device_create(struct ddb *dev)
return -ENOMEM; return -ENOMEM;
mutex_lock(&ddb_mutex); mutex_lock(&ddb_mutex);
dev->nr = ddb_num; dev->nr = ddb_num;
atomic_set(&dev->ddb_dev_users, 1);
ddbs[dev->nr] = dev; ddbs[dev->nr] = dev;
dev->ddb_dev = device_create(&ddb_class, dev->dev, dev->ddb_dev = device_create(&ddb_class, dev->dev,
MKDEV(ddb_major, dev->nr), MKDEV(ddb_major, dev->nr),
@ -4315,7 +4162,7 @@ static void gtl_link_handler(void *priv)
struct ddb *dev = (struct ddb *)priv; struct ddb *dev = (struct ddb *)priv;
u32 regs = dev->link[0].info->regmap->gtl->base; u32 regs = dev->link[0].info->regmap->gtl->base;
dev_info(dev->dev, "GT link change: %u\n", dev_info(dev->dev, "GT link changed to %u\n",
(1 & ddbreadl(dev, regs))); (1 & ddbreadl(dev, regs)));
} }
@ -4342,7 +4189,9 @@ static void link_tasklet(unsigned long data)
static void gtl_irq_handler(void *priv) static void gtl_irq_handler(void *priv)
{ {
struct ddb_link *link = (struct ddb_link *)priv; struct ddb_link *link = (struct ddb_link *)priv;
#if 1 #ifdef USE_LINK_TASKLET
tasklet_schedule(&link->tasklet);
#else
struct ddb *dev = link->dev; struct ddb *dev = link->dev;
u32 s, l = link->nr, tag = DDB_LINK_TAG(link->nr); u32 s, l = link->nr, tag = DDB_LINK_TAG(link->nr);
@ -4354,8 +4203,6 @@ static void gtl_irq_handler(void *priv)
LINK_IRQ_HANDLE(l, 3); LINK_IRQ_HANDLE(l, 3);
LINK_IRQ_HANDLE(l, 24); LINK_IRQ_HANDLE(l, 24);
} }
#else
tasklet_schedule(&link->tasklet);
#endif #endif
} }
@ -4399,7 +4246,7 @@ static int ddb_gtl_init_link(struct ddb *dev, u32 l)
subid & 0xffff, subid >> 16); subid & 0xffff, subid >> 16);
if (link->info->type != DDB_OCTOPUS_MAX_CT && if (link->info->type != DDB_OCTOPUS_MAX_CT &&
link->info->type != DDB_OCTOPUS_MAX && link->info->type != DDB_OCTOPUS_MAX &&
link->info->type != DDB_OCTOPUS_MCI ) { link->info->type != DDB_OCTOPUS_MCI) {
dev_info(dev->dev, dev_info(dev->dev,
"Detected GT link but found invalid ID %08x. You might have to update (flash) the add-on card first.", "Detected GT link but found invalid ID %08x. You might have to update (flash) the add-on card first.",
id); id);
@ -4661,6 +4508,7 @@ int ddb_exit_ddbridge(int stage, int error)
default: default:
case 2: case 2:
destroy_workqueue(ddb_wq); destroy_workqueue(ddb_wq);
/* fallthrough */
case 1: case 1:
ddb_class_destroy(); ddb_class_destroy();
} }

View File

@ -801,7 +801,7 @@ static const struct ddb_device_id ddb_device_ids[] = {
DDB_DEVID(0x0013, 0x0044, ddb_ci_s2_pro_a), DDB_DEVID(0x0013, 0x0044, ddb_ci_s2_pro_a),
DDB_DEVID(0x0020, 0x0012, ddb_gtl_mini), DDB_DEVID(0x0020, 0x0012, ddb_gtl_mini),
/* Modulators */ /* Modulators */
DDB_DEVID(0x0201, 0x0001, ddb_mod), DDB_DEVID(0x0201, 0x0001, ddb_mod),
DDB_DEVID(0x0201, 0x0002, ddb_mod), DDB_DEVID(0x0201, 0x0002, ddb_mod),
DDB_DEVID(0x0201, 0x0004, ddb_mod_4), /* dummy entry ! */ DDB_DEVID(0x0201, 0x0004, ddb_mod_4), /* dummy entry ! */
@ -821,19 +821,22 @@ static const struct ddb_device_id ddb_device_ids[] = {
DDB_DEVID(0x0323, 0xffff, ddb_none), DDB_DEVID(0x0323, 0xffff, ddb_none),
DDB_DEVID(0x0328, 0xffff, ddb_none), DDB_DEVID(0x0328, 0xffff, ddb_none),
DDB_DEVID(0x0329, 0xffff, ddb_octopro_hdin), DDB_DEVID(0x0329, 0xffff, ddb_octopro_hdin),
DDB_DEVID(0xffff, 0xffff, ddb_none),
}; };
const struct ddb_info *get_ddb_info(u16 vendor, u16 device, const struct ddb_info *get_ddb_info(u16 vendor, u16 device,
u16 subvendor, u16 subdevice) u16 subvendor, u16 subdevice)
{ {
int i; int i;
for (i = 0; i < ARRAY_SIZE(ddb_device_ids); i++) { for (i = 0; i < ARRAY_SIZE(ddb_device_ids); i++) {
const struct ddb_device_id *id = &ddb_device_ids[i]; const struct ddb_device_id *id = &ddb_device_ids[i];
if (vendor == id->vendor && if (vendor == id->vendor &&
device == id->device && device == id->device &&
subvendor == id->subvendor && (subvendor == id->subvendor ||
id->subvendor == 0xffff) &&
(subdevice == id->subdevice || (subdevice == id->subdevice ||
id->subdevice == 0xffff)) id->subdevice == 0xffff))
return id->info; return id->info;

View File

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

View File

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

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* ddbridge-io.c: Digital Devices bridge I/O functions * ddbridge-io.c: Digital Devices bridge I/O functions
* *
@ -65,6 +66,8 @@ u32 ddbreadl(struct ddb *dev, u32 adr)
u32 val, l = (adr >> DDB_LINK_SHIFT) & 3; u32 val, l = (adr >> DDB_LINK_SHIFT) & 3;
struct ddb_link *link = &dev->link[l]; struct ddb_link *link = &dev->link[l];
if (!link->regs)
return 0;
spin_lock_irqsave(&link->lock, flags); spin_lock_irqsave(&link->lock, flags);
gtlw(link); gtlw(link);
ddblwritel0(link, adr & 0xfffc, link->regs + 0x14); ddblwritel0(link, adr & 0xfffc, link->regs + 0x14);
@ -84,6 +87,8 @@ void ddbwritel(struct ddb *dev, u32 val, u32 adr)
u32 l = (adr >> DDB_LINK_SHIFT); u32 l = (adr >> DDB_LINK_SHIFT);
struct ddb_link *link = &dev->link[l]; struct ddb_link *link = &dev->link[l];
if (!link->regs)
return;
spin_lock_irqsave(&link->lock, flags); spin_lock_irqsave(&link->lock, flags);
gtlw(link); gtlw(link);
ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14); ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14);

View File

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

View File

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

View File

@ -360,17 +360,17 @@ static int __devinit ddb_probe(struct pci_dev *pdev,
if (dev->link[0].info->type == DDB_MOD if (dev->link[0].info->type == DDB_MOD
&& dev->link[0].info->version == 2) { && dev->link[0].info->version == 2) {
u32 lic = ddbreadl(dev, 0x1c) & 7; u32 lic = ddbreadl(dev, 0x1c) & 7;
switch (lic) { switch (lic) {
case 0: case 0:
dev->link[0].info = dev->link[0].info =
get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0000); get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0000);
break; break;
case 1: case 1:
dev->link[0].info = dev->link[0].info =
get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0003); get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0003);
break; break;
case 3: case 3:
dev->link[0].info = dev->link[0].info =
get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0002); get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0002);
break; break;
@ -458,11 +458,9 @@ static pci_ers_result_t ddb_pci_error_detected(struct pci_dev *pdev,
{ {
switch (state) { switch (state) {
case pci_channel_io_frozen: case pci_channel_io_frozen:
return PCI_ERS_RESULT_CAN_RECOVER; return PCI_ERS_RESULT_CAN_RECOVER;
case pci_channel_io_perm_failure: case pci_channel_io_perm_failure:
return PCI_ERS_RESULT_DISCONNECT; return PCI_ERS_RESULT_DISCONNECT;
break;
case pci_channel_io_normal: case pci_channel_io_normal:
default: default:
break; break;

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* ddbridge-max.c: Digital Devices MAX card line support functions * ddbridge-max.c: Digital Devices MAX card line support functions
* *
@ -67,7 +68,7 @@ static int max_emulate_switch(struct dvb_frontend *fe,
{ {
int input; int input;
if (len !=4) if (len != 4)
return -1; return -1;
if ((cmd[0] != 0xe0) || (cmd[1] != 0x10) || (cmd[2] != 0x39)) if ((cmd[0] != 0xe0) || (cmd[1] != 0x10) || (cmd[2] != 0x39))
@ -357,6 +358,29 @@ static int max_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage)
static int max_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) static int max_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
{ {
struct ddb_input *input = fe->sec_priv;
struct ddb_port *port = input->port;
struct ddb *dev = port->dev;
u32 tag = DDB_LINK_TAG(port->lnr);
struct ddb_dvb *dvb = &port->dvb[input->nr & 1];
u32 fmode = dev->link[port->lnr].lnb.fmode;
mutex_lock(&dev->link[port->lnr].lnb.lock);
switch (fmode) {
default:
case 0:
case 3:
ddbwritel(dev, arg ? 0x34 : 0x01, tag | LNB_CONTROL(dvb->input));
break;
case 1:
case 2:
ddbwritel(dev, arg ? 0x34 : 0x01, tag | LNB_CONTROL(0));
ddbwritel(dev, arg ? 0x34 : 0x01, tag | LNB_CONTROL(1));
ddbwritel(dev, arg ? 0x34 : 0x01, tag | LNB_CONTROL(2));
ddbwritel(dev, arg ? 0x34 : 0x01, tag | LNB_CONTROL(3));
break;
}
mutex_unlock(&dev->link[port->lnr].lnb.lock);
return 0; return 0;
} }
@ -467,9 +491,6 @@ int ddb_fe_attach_mxl5xx(struct ddb_input *input)
/* MAX MCI related functions */ /* MAX MCI related functions */
extern struct mci_cfg ddb_max_sx8_cfg;
extern struct mci_cfg ddb_max_m4_cfg;
int ddb_fe_attach_mci(struct ddb_input *input, u32 type) int ddb_fe_attach_mci(struct ddb_input *input, u32 type)
{ {
struct ddb *dev = input->port->dev; struct ddb *dev = input->port->dev;
@ -479,7 +500,7 @@ int ddb_fe_attach_mci(struct ddb_input *input, u32 type)
int demod, tuner; int demod, tuner;
struct mci_cfg cfg; struct mci_cfg cfg;
int fm = fmode; int fm = fmode;
demod = input->nr; demod = input->nr;
tuner = demod & 3; tuner = demod & 3;
switch (type) { switch (type) {

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0
/* /*
* ddbridge-mci.c: Digital Devices microcode interface * ddbridge-mci.c: Digital Devices microcode interface
* *
@ -38,7 +39,7 @@ static int mci_reset(struct mci *state)
msleep(300); msleep(300);
ddblwritel(link, 0, MCI_CONTROL); ddblwritel(link, 0, MCI_CONTROL);
while(1) { while (1) {
status = ddblreadl(link, MCI_CONTROL); status = ddblreadl(link, MCI_CONTROL);
if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY) if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY)
break; break;
@ -46,7 +47,7 @@ static int mci_reset(struct mci *state)
break; break;
msleep(50); msleep(50);
} }
if ((status & MCI_CONTROL_READY) == 0 ) if ((status & MCI_CONTROL_READY) == 0)
return -1; return -1;
if (link->ids.device == 0x0009 || link->ids.device == 0x000b) if (link->ids.device == 0x0009 || link->ids.device == 0x000b)
ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG); ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG);
@ -71,7 +72,7 @@ static int ddb_mci_cmd_raw_unlocked(struct mci *state,
struct ddb_link *link = state->base->link; struct ddb_link *link = state->base->link;
u32 i, val; u32 i, val;
unsigned long stat; unsigned long stat;
val = ddblreadl(link, MCI_CONTROL); val = ddblreadl(link, MCI_CONTROL);
if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND)) if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND))
return -EIO; return -EIO;
@ -80,19 +81,21 @@ static int ddb_mci_cmd_raw_unlocked(struct mci *state,
ddblwritel(link, cmd[i], MCI_COMMAND + i * 4); ddblwritel(link, cmd[i], MCI_COMMAND + i * 4);
val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT); val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT);
ddblwritel(link, val, MCI_CONTROL); ddblwritel(link, val, MCI_CONTROL);
stat = wait_for_completion_timeout(&state->base->completion, HZ); stat = wait_for_completion_timeout(&state->base->completion, HZ);
if (stat == 0) { if (stat == 0) {
u32 istat = ddblreadl(link, INTERRUPT_STATUS); u32 istat = ddblreadl(link, INTERRUPT_STATUS);
printk("MCI timeout\n"); dev_err(state->base->link->dev->dev, "MCI timeout\n");
val = ddblreadl(link, MCI_CONTROL); val = ddblreadl(link, MCI_CONTROL);
if (val == 0xffffffff) { if (val == 0xffffffff) {
printk("Lost PCIe link!\n"); dev_err(state->base->link->dev->dev,
"Lost PCIe link!\n");
return -EIO; return -EIO;
} else { } else {
printk("DDBridge IRS %08x link %u\n", istat, link->nr); dev_err(state->base->link->dev->dev,
if (istat & 1) "DDBridge IRS %08x link %u\n", istat, link->nr);
if (istat & 1)
ddblwritel(link, istat, INTERRUPT_ACK); ddblwritel(link, istat, INTERRUPT_ACK);
if (link->nr) if (link->nr)
ddbwritel(link->dev, 0xffffff, INTERRUPT_ACK); ddbwritel(link->dev, 0xffffff, INTERRUPT_ACK);
@ -110,7 +113,7 @@ int ddb_mci_cmd_unlocked(struct mci *state,
{ {
u32 *cmd = (u32 *) command; u32 *cmd = (u32 *) command;
u32 *res = (u32 *) result; u32 *res = (u32 *) result;
return ddb_mci_cmd_raw_unlocked(state, cmd, sizeof(*command)/sizeof(u32), return ddb_mci_cmd_raw_unlocked(state, cmd, sizeof(*command)/sizeof(u32),
res, sizeof(*result)/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) struct mci_result *result, u32 result_len)
{ {
int stat; int stat;
mutex_lock(&state->base->mci_lock); mutex_lock(&state->base->mci_lock);
stat = ddb_mci_cmd_raw_unlocked(state, stat = ddb_mci_cmd_raw_unlocked(state,
(u32 *)command, command_len, (u32 *)command, command_len,
@ -186,8 +189,7 @@ int ddb_mci_get_snr(struct dvb_frontend *fe)
p->cnr.len = 1; p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL; p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].svalue = (s64) mci-> p->cnr.stat[0].svalue = (s64) mci->signal_info.dvbs2_signal_info.signal_to_noise * 10;
signal_info.dvbs2_signal_info.signal_to_noise * 10;
return 0; return 0;
} }
@ -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_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_10,
ROLLOFF_5, ROLLOFF_15, ROLLOFF_35, ROLLOFF_35 ROLLOFF_5, ROLLOFF_15, ROLLOFF_35, ROLLOFF_35
}; };
p->frequency = p->frequency =
mci->signal_info.dvbs2_signal_info.frequency; mci->signal_info.dvbs2_signal_info.frequency;
switch (p->delivery_system) { switch (p->delivery_system) {
@ -259,23 +261,31 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p)
{ {
u32 pls_code = u32 pls_code =
mci->signal_info.dvbs2_signal_info.pls_code; mci->signal_info.dvbs2_signal_info.pls_code;
p->frequency = p->frequency =
mci->signal_info.dvbs2_signal_info.frequency / 1000; mci->signal_info.dvbs2_signal_info.frequency / 1000;
p->delivery_system = p->delivery_system =
(mci->signal_info.dvbs2_signal_info.standard == 2) ? (mci->signal_info.dvbs2_signal_info.standard == 2) ?
SYS_DVBS2 : SYS_DVBS; SYS_DVBS2 : SYS_DVBS;
if (mci->signal_info.dvbs2_signal_info.standard == 2) { if (mci->signal_info.dvbs2_signal_info.standard == 2) {
u32 modcod = (0x7c & pls_code) >> 2; u32 modcod;
p->delivery_system = SYS_DVBS2; p->delivery_system = SYS_DVBS2;
p->rolloff =
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];
p->transmission_mode = pls_code; p->transmission_mode = pls_code;
p->rolloff =
ro_lut[mci->signal_info.dvbs2_signal_info.roll_off & 7];
p->pilot = (pls_code & 1) ? PILOT_ON : PILOT_OFF;
if (pls_code & 0x80) {
/* no suitable values defined in Linux DVB API yet */
/* modcod = (0x7f & pls_code) >> 1; */
p->fec_inner = FEC_NONE;
p->modulation = 0;
if (pls_code >= 250)
p->pilot = PILOT_ON;
} else {
modcod = (0x7c & pls_code) >> 2;
p->fec_inner = modcod2fec[modcod];
p->modulation = modcod2mod[modcod];
}
} else { } else {
p->delivery_system = SYS_DVBS; p->delivery_system = SYS_DVBS;
p->rolloff = ROLLOFF_35; p->rolloff = ROLLOFF_35;
@ -314,8 +324,8 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p)
p->cnr.len = 1; p->cnr.len = 1;
p->cnr.stat[0].scale = FE_SCALE_DECIBEL; p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
p->cnr.stat[0].svalue = (s64) mci-> p->cnr.stat[0].svalue = (s64)
signal_info.dvbs2_signal_info.signal_to_noise * 10; mci->signal_info.dvbs2_signal_info.signal_to_noise * 10;
p->strength.len = 1; p->strength.len = 1;
p->strength.stat[0].scale = FE_SCALE_DECIBEL; p->strength.stat[0].scale = FE_SCALE_DECIBEL;
@ -388,6 +398,7 @@ struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg
state->nr = nr; state->nr = nr;
state->demod = nr; state->demod = nr;
state->tuner = tuner; state->tuner = tuner;
state->input = input;
if (cfg->init) if (cfg->init)
cfg->init(state); cfg->init(state);
return &state->fe; return &state->fe;

View File

@ -148,11 +148,12 @@
#define M4_CMD_GET_IDS (0x51) #define M4_CMD_GET_IDS (0x51)
#define M4_CMD_GET_DVBT_TPS (0x52) #define M4_CMD_GET_DVBT_TPS (0x52)
#define MCI_CMD_GET_BBHEADER (0x53) #define MCI_CMD_GET_BBHEADER (0x53)
#define M4_CMD_GET_BBHEADER (MCI_CMD_GET_BBHEADER)
#define M4_CMD_GET_ISDBT_TMCC (0x54) #define M4_CMD_GET_ISDBT_TMCC (0x54)
#define M4_CMD_GET_ISDBS_TMCC (0x55) #define M4_CMD_GET_ISDBS_TMCC (0x55)
#define M4_CMD_GET_ISDBC_TSMF (0x56) #define M4_CMD_GET_ISDBC_TSMF (0x56)
#define M4_CMD_GET_BBHEADER (MCI_CMD_GET_BBHEADER)
#define M4_L1INFO_SEL_PRE (0) #define M4_L1INFO_SEL_PRE (0)
#define M4_L1INFO_SEL_DSINFO (1) #define M4_L1INFO_SEL_DSINFO (1)
#define M4_L1INFO_SEL_PLPINFO (2) #define M4_L1INFO_SEL_PLPINFO (2)
@ -180,6 +181,7 @@
#define M4_SIGNALINFO_FLAG_CHANGE (0x01) #define M4_SIGNALINFO_FLAG_CHANGE (0x01)
#define M4_SIGNALINFO_FLAG_EWS (0x02) #define M4_SIGNALINFO_FLAG_EWS (0x02)
#define SX8_ROLLOFF_35 0
#define SX8_ROLLOFF_25 1 #define SX8_ROLLOFF_25 1
#define SX8_ROLLOFF_20 2 #define SX8_ROLLOFF_20 2
#define SX8_ROLLOFF_15 5 #define SX8_ROLLOFF_15 5
@ -205,7 +207,7 @@ struct mci_command {
u32 params[31]; u32 params[31];
struct { struct {
u8 flags; /* Bit 0: DVB-S Enabled, 1: DVB-S2 Enabled, u8 flags; /* Bit 0: DVB-S Enabled, 1: DVB-S2 Enabled,
6: FrequencyRange, 7: InputStreamID */ 5: ChannelBonding, 6: FrequencyRange, 7: InputStreamID */
u8 s2_modulation_mask; /* Bit 0 : QPSK, 1: 8PSK/8APSK, u8 s2_modulation_mask; /* Bit 0 : QPSK, 1: 8PSK/8APSK,
2 : 16APSK, 3: 32APSK, 4: 64APSK, 2 : 16APSK, 3: 32APSK, 4: 64APSK,
5: 128APSK, 6: 256APSK */ 5: 128APSK, 6: 256APSK */
@ -217,6 +219,9 @@ struct mci_command {
u8 rsvd2[3]; u8 rsvd2[3];
u32 scrambling_sequence_index; u32 scrambling_sequence_index;
u32 frequency_range; u32 frequency_range;
u8 channel_bonding_config; /* Bit 7: IsSlave, Bit 5..4: MasterDemod,
bit 0: Num channels - 2.
(must be set on all channels to same value) */
} dvbs2_search; } dvbs2_search;
struct { struct {
@ -306,11 +311,10 @@ struct mci_command {
u16 point; u16 point;
} get_iq_symbol; } get_iq_symbol;
struct { struct {
uint8_t flags; /* Bit 0 : 0 = VTM/SDR, 1 = SCAN, uint8_t flags; /* Bit 0 : 0 = VTM/SDR, 1 = SCAN,
Bit 1: 1 = Disable AGC, Bit 2: Bit 1: 1 = Disable AGC,
1 = Set Gain. */ Bit 2: 1 = Set Gain. */
uint8_t roll_off; uint8_t roll_off;
uint8_t rsvd1; uint8_t rsvd1;
uint8_t rsvd2; uint8_t rsvd2;
@ -319,7 +323,7 @@ struct mci_command {
uint8_t gain; /* Gain in 0.25 dB Steps */ uint8_t gain; /* Gain in 0.25 dB Steps */
/* Frequency, symbolrate and gain can be schanged while running */ /* Frequency, symbolrate and gain can be schanged while running */
} sx8_start_iq; } sx8_start_iq;
struct { struct {
uint8_t flags; uint8_t flags;
/* Bit 0:1 Preamp Mode; 0 = Preamp AGC, 1 == Minimum (~ -17dB) , /* Bit 0:1 Preamp Mode; 0 = Preamp AGC, 1 == Minimum (~ -17dB) ,
@ -393,6 +397,21 @@ struct mci_result {
u32 ber_denominator; u32 ber_denominator;
} dvbs2_signal_info; } dvbs2_signal_info;
struct {
u8 modcod;
u8 rsvd0[2];
u8 flags; /* Bit 0: TMCC changed, Bit 1: EWS */
u32 frequency; /* actual frequency in Hz */
u32 symbol_rate; /* actual symbolrate in Hz */
s16 channel_power; /* channel power in dBm x 100 */
s16 band_power; /*/ band power in dBm x 100 */
s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */
s16 rsvd2;
u32 packet_errors; /* Counter for packet errors. (set to 0 on Start command) */
u32 ber_numerator; /* Bit error rate: PreRS in DVB-S, PreBCH in DVB-S2X */
u32 ber_denominator;
} isdbs_signal_info;
struct { struct {
u8 constellation; u8 constellation;
u8 rsvd0[2]; u8 rsvd0[2];
@ -644,14 +663,13 @@ struct mci_result {
u8 min_input_stream_id; u8 min_input_stream_id;
u8 max_input_stream_id; u8 max_input_stream_id;
} BBHeader; } BBHeader;
struct { struct {
u8 Mode; // FFT Mode 1,2,3 u8 Mode; // FFT Mode 1,2,3
u8 GuardInterval; // 1/32, 1/16, 1/8, /14 u8 GuardInterval; // 1/32, 1/16, 1/8, /14
u8 TMCCInfo[13]; // TMCC B20 - B121, byte 0 bit 7: B20, byte 12 bit 2: B121
u8 TMCCInfo[13]; // TMCC B20 - B121, byte 0 bit 7: B20, byte 12 bit 2: B121
} ISDBT_TMCCInfo; } ISDBT_TMCCInfo;
struct { struct {
u8 Change; // 5 bits, increments with every change u8 Change; // 5 bits, increments with every change
struct { struct {
@ -710,7 +728,7 @@ struct mci_result {
/* DVB-T2 L1-Post Signalling Data ( ETSI EN 302 755 V1.4.1 Chapter 7.2.3 ) */ /* DVB-T2 L1-Post Signalling Data ( ETSI EN 302 755 V1.4.1 Chapter 7.2.3 ) */
#define L1POST_SUB_SLICES_PER_FRAME(p) (((u16)(p)[ 0] & 0x7F) | (p)[ 1]) #define L1POST_SUB_SLICES_PER_FRAME(p) (((u16)(p)[0] & 0x7F) | (p)[1])
#define L1POST_NUM_PLP(p) ((p)[2] & 0xFF) #define L1POST_NUM_PLP(p) ((p)[2] & 0xFF)
#define L1POST_NUM_AUX(p) ((p)[3] & 0x0F) #define L1POST_NUM_AUX(p) ((p)[3] & 0x0F)
#define L1POST_AUX_CONFIG_RFU(p) ((p)[4] & 0xFF) #define L1POST_AUX_CONFIG_RFU(p) ((p)[4] & 0xFF)
@ -750,8 +768,6 @@ struct mci_base {
void *key; void *key;
struct ddb_link *link; struct ddb_link *link;
struct completion completion; struct completion completion;
struct i2c_adapter *i2c;
struct mutex i2c_lock;
struct mutex tuner_lock; struct mutex tuner_lock;
struct mutex mci_lock; struct mutex mci_lock;
int count; int count;
@ -759,6 +775,7 @@ struct mci_base {
}; };
struct mci { struct mci {
struct ddb_io *input;
struct mci_base *base; struct mci_base *base;
struct dvb_frontend fe; struct dvb_frontend fe;
int nr; int nr;
@ -787,4 +804,7 @@ int ddb_mci_get_info(struct mci *mci);
int ddb_mci_get_strength(struct dvb_frontend *fe); int ddb_mci_get_strength(struct dvb_frontend *fe);
void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p); void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p);
extern struct mci_cfg ddb_max_sx8_cfg;
extern struct mci_cfg ddb_max_m4_cfg;
#endif #endif

View File

@ -435,7 +435,7 @@ static int mod_setup_max2871(struct ddb *dev, u32 *reg)
if (j == 4) if (j == 4)
val &= 0xFFFFFEDF; val &= 0xFFFFFEDF;
status = mod_write_max2871(dev, reg[j]); status = mod_write_max2871(dev, val);
if (status) if (status)
break; break;
msleep(30); msleep(30);
@ -1516,11 +1516,12 @@ static int mod3_set_ari(struct ddb_mod *mod, u32 rate)
static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate) static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate)
{ {
u32 cic, inc; u32 cic, inc, bypass = 0;
switch (rate) { switch (rate) {
/* 2^31 * freq*4*cic / 245.76Mhz */
case SYS_DVBT_6: case SYS_DVBT_6:
inc = 1917396114; inc = 0x72492492;
cic = 8; cic = 8;
break; break;
case SYS_DVBT_7: case SYS_DVBT_7:
@ -1532,15 +1533,45 @@ static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate)
inc = 1917396114; inc = 1917396114;
cic = 6; cic = 6;
break; break;
case SYS_DVBC_6900:
inc = 0x73000000; //1929379840;
cic = 8;
break;
case 9:
inc = 0x47e00000; //1929379840;
cic = 10;
bypass = 2;
break;
case SYS_J83B_64_6: /* 5056941 */
inc = 0x695a5a1d;
cic = 10;
break;
case SYS_J83B_256_6: /* 5360537 */
inc = 0x6fad87da;
cic = 10;
break;
case SYS_ISDBT_6: case SYS_ISDBT_6:
inc = 1988410754; inc = 0x7684BD82; //1988410754;
cic = 7; cic = 7;
break; break;
case SYS_DVBS2_22:
inc = 0x72955555; // 1922389333;
cic = 5;
bypass = 2;
break;
case SYS_DVBS2_24:
inc = 0x7d000000;
cic = 5;
bypass = 2;
break;
default: default:
return -EINVAL; return -EINVAL;
} }
ddbwritel(mod->port->dev, inc, SDR_CHANNEL_ARICW(mod->port->nr)); ddbwritel(mod->port->dev, inc, SDR_CHANNEL_ARICW(mod->port->nr));
ddbwritel(mod->port->dev, cic << 8, SDR_CHANNEL_CONFIG(mod->port->nr)); ddbwritel(mod->port->dev, (cic << 8) | (bypass << 4),
SDR_CHANNEL_CONFIG(mod->port->nr));
return 0; return 0;
} }
@ -1870,7 +1901,7 @@ static int rfdac_init(struct ddb *dev)
} }
if (tmp & 0x80) if (tmp & 0x80)
return -1; return -1;
dev_info(dev->dev, "sync %d:%08x\n", i, tmp); //dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
ddbwritel(dev, RFDAC_CMD_RESET, RFDAC_CONTROL); ddbwritel(dev, RFDAC_CMD_RESET, RFDAC_CONTROL);
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
msleep(20); msleep(20);
@ -1880,7 +1911,7 @@ static int rfdac_init(struct ddb *dev)
} }
if (tmp & 0x80) if (tmp & 0x80)
return -1; return -1;
dev_info(dev->dev, "sync %d:%08x\n", i, tmp); //dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
ddbwritel(dev, RFDAC_CMD_SETUP, RFDAC_CONTROL); ddbwritel(dev, RFDAC_CMD_SETUP, RFDAC_CONTROL);
for (i = 0; i < 10; i++) { for (i = 0; i < 10; i++) {
msleep(20); msleep(20);
@ -1890,7 +1921,7 @@ static int rfdac_init(struct ddb *dev)
} }
if (tmp & 0x80) if (tmp & 0x80)
return -1; return -1;
dev_info(dev->dev, "sync %d:%08x\n", i, tmp); //dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
ddbwritel(dev, 0x01, JESD204B_BASE); ddbwritel(dev, 0x01, JESD204B_BASE);
for (i = 0; i < 400; i++) { for (i = 0; i < 400; i++) {
msleep(20); msleep(20);
@ -1898,7 +1929,7 @@ static int rfdac_init(struct ddb *dev)
if ((tmp & 0xc0000000) == 0xc0000000) if ((tmp & 0xc0000000) == 0xc0000000)
break; break;
} }
dev_info(dev->dev, "sync %d:%08x\n", i, tmp); //dev_info(dev->dev, "sync %d:%08x\n", i, tmp);
if ((tmp & 0xc0000000) != 0xc0000000) if ((tmp & 0xc0000000) != 0xc0000000)
return -1; return -1;
return 0; return 0;

View File

@ -1,9 +1,9 @@
/* /*
* ddbridge-ns.c: Digital Devices PCIe bridge driver net streaming * ddbridge-ns.c: Digital Devices PCIe bridge driver net streaming
* *
* Copyright (C) 2010-2017Marcus Metzler <mocm@metzlerbros.de> * Copyright (C) 2010-2017 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de> * Ralph Metzler <rjkm@metzlerbros.de>
* Digital Devices GmbH
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License * modify it under the terms of the GNU General Public License
@ -441,11 +441,11 @@ static int ns_start(struct dvbnss *nss)
reg |= 0x40; reg |= 0x40;
if (nss->params.flags & DVB_NS_IPV6) if (nss->params.flags & DVB_NS_IPV6)
reg |= 0x80; reg |= 0x80;
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
STREAM_CONTROL(dns->nr));
if (dns->fe != input) if (dns->fe != input)
ddb_dvb_ns_input_start(dns->fe); ddb_dvb_ns_input_start(dns->fe);
ddb_dvb_ns_input_start(input); ddb_dvb_ns_input_start(input);
ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16),
STREAM_CONTROL(dns->nr));
return 0; return 0;
} }

View File

@ -232,6 +232,7 @@
#define TS_CONTROL(_io) ((_io)->regs + 0x00) #define TS_CONTROL(_io) ((_io)->regs + 0x00)
#define TS_CONTROL2(_io) ((_io)->regs + 0x04) #define TS_CONTROL2(_io) ((_io)->regs + 0x04)
#define TS_STAT(_io) ((_io)->regs + 0x08)
#define TS_INPUT_CONTROL_ENABLE (0x00000001) #define TS_INPUT_CONTROL_ENABLE (0x00000001)
#define TS_INPUT_CONTROL_RESET (0x00000002) #define TS_INPUT_CONTROL_RESET (0x00000002)

View File

@ -138,7 +138,6 @@ static int read_status(struct dvb_frontend *fe, enum fe_status *status)
dvbs2_bits_per_symbol[ dvbs2_bits_per_symbol[
state->mci.signal_info. state->mci.signal_info.
dvbs2_signal_info.pls_code]; dvbs2_signal_info.pls_code];
//printk("PLS %02x\n", state->mci.signal_info.dvbs2_signal_info.pls_code);
} else } else
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0; sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
} }
@ -162,7 +161,10 @@ static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on)
static int stop_iq(struct dvb_frontend *fe) static int stop_iq(struct dvb_frontend *fe)
{ {
struct sx8 *state = fe->demodulator_priv; struct sx8 *state = fe->demodulator_priv;
struct mci_base *mci_base = state->mci.base;
struct sx8_base *sx8_base = (struct sx8_base *) mci_base;
struct mci_command cmd; struct mci_command cmd;
u32 input = state->mci.tuner;
if (!state->iq_started) if (!state->iq_started)
return -1; return -1;
@ -171,7 +173,19 @@ static int stop_iq(struct dvb_frontend *fe)
cmd.demod = state->mci.demod; cmd.demod = state->mci.demod;
ddb_mci_cmd(&state->mci, &cmd, NULL); ddb_mci_cmd(&state->mci, &cmd, NULL);
ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL); ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL);
mutex_lock(&mci_base->tuner_lock);
sx8_base->tuner_use_count[input]--;
if (!sx8_base->tuner_use_count[input])
mci_set_tuner(fe, input, 0);
if (state->mci.demod != SX8_DEMOD_NONE) {
sx8_base->demod_in_use[state->mci.demod] = 0;
state->mci.demod = SX8_DEMOD_NONE;
}
sx8_base->used_ldpc_bitrate[state->mci.nr] = 0;
sx8_base->iq_mode = 0;
state->iq_started = 0; state->iq_started = 0;
mutex_unlock(&mci_base->tuner_lock);
return 0; return 0;
} }
@ -226,7 +240,14 @@ static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
u32 input = state->mci.tuner; u32 input = state->mci.tuner;
u32 bits_per_symbol = 0; u32 bits_per_symbol = 0;
int i = -1, stat = 0; int i = -1, stat = 0;
struct ddb_link *link = state->mci.base->link;
if (link->ids.device == 0x000b) {
/* Mask out higher modulations and MIS for Basic
or search command will fail */
modmask &= 3;
p->stream_id = NO_STREAM_ID_FILTER;
}
if (p->symbol_rate >= MCLK / 2) if (p->symbol_rate >= MCLK / 2)
flags &= ~1; flags &= ~1;
if ((flags & 3) == 0) if ((flags & 3) == 0)
@ -241,7 +262,6 @@ static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config)
bits_per_symbol++; bits_per_symbol++;
} }
} }
mutex_lock(&mci_base->tuner_lock); mutex_lock(&mci_base->tuner_lock);
if (sx8_base->iq_mode) { if (sx8_base->iq_mode) {
stat = -EBUSY; stat = -EBUSY;
@ -334,7 +354,8 @@ unlock:
cmd.tuner = state->mci.tuner; cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod; cmd.demod = state->mci.demod;
cmd.output = state->mci.nr; cmd.output = state->mci.nr;
if (p->stream_id == 0x80000000) if ((p->stream_id != NO_STREAM_ID_FILTER) &&
(p->stream_id & 0x80000000))
cmd.output |= 0x80; cmd.output |= 0x80;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL); stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
if (stat) if (stat)
@ -355,34 +376,36 @@ static int start_iq(struct dvb_frontend *fe, u32 flags,
u32 input = state->mci.tuner; u32 input = state->mci.tuner;
int i, stat = 0; int i, stat = 0;
mutex_lock(&mci_base->tuner_lock); if (!state->iq_started) {
if (sx8_base->iq_mode) { mutex_lock(&mci_base->tuner_lock);
stat = -EBUSY; if (sx8_base->iq_mode) {
goto unlock; stat = -EBUSY;
goto unlock;
}
for (i = 0; i < SX8_DEMOD_NUM; i++)
if (sx8_base->demod_in_use[i])
used_demods++;
if (used_demods > 0) {
stat = -EBUSY;
goto unlock;
}
state->mci.demod = 0;
if (!sx8_base->tuner_use_count[input])
mci_set_tuner(fe, input, 1);
sx8_base->tuner_use_count[input]++;
sx8_base->iq_mode = (ts_config > 1);
unlock:
mutex_unlock(&mci_base->tuner_lock);
if (stat)
return stat;
} }
for (i = 0; i < SX8_DEMOD_NUM; i++)
if (sx8_base->demod_in_use[i])
used_demods++;
if (used_demods > 0) {
stat = -EBUSY;
goto unlock;
}
state->mci.demod = 0;
if (!sx8_base->tuner_use_count[input])
mci_set_tuner(fe, input, 1);
sx8_base->tuner_use_count[input]++;
sx8_base->iq_mode = (ts_config > 1);
unlock:
mutex_unlock(&mci_base->tuner_lock);
if (stat)
return stat;
memset(&cmd, 0, sizeof(cmd)); memset(&cmd, 0, sizeof(cmd));
cmd.command = SX8_CMD_START_IQ; cmd.command = SX8_CMD_START_IQ;
cmd.sx8_start_iq.flags = flags; cmd.sx8_start_iq.flags = flags >> 8;
cmd.sx8_start_iq.roll_off = roll_off; cmd.sx8_start_iq.roll_off = roll_off;
cmd.sx8_start_iq.frequency = p->frequency * 1000; cmd.sx8_start_iq.frequency = p->frequency * 1000;
cmd.sx8_start_iq.symbol_rate = p->symbol_rate; cmd.sx8_start_iq.symbol_rate = p->symbol_rate;
cmd.sx8_start_iq.gain = flags & 0xff;
cmd.tuner = state->mci.tuner; cmd.tuner = state->mci.tuner;
cmd.demod = state->mci.demod; cmd.demod = state->mci.demod;
stat = ddb_mci_cmd(&state->mci, &cmd, NULL); stat = ddb_mci_cmd(&state->mci, &cmd, NULL);
@ -392,18 +415,26 @@ unlock:
return stat; return stat;
} }
static int set_lna(struct dvb_frontend *fe)
{
printk("set_lna\n");
return 0;
}
static int set_parameters(struct dvb_frontend *fe) static int set_parameters(struct dvb_frontend *fe)
{ {
int stat = 0; int stat = 0;
struct sx8 *state = fe->demodulator_priv; struct sx8 *state = fe->demodulator_priv;
struct dtv_frontend_properties *p = &fe->dtv_property_cache; struct dtv_frontend_properties *p = &fe->dtv_property_cache;
u32 ts_config = SX8_TSCONFIG_MODE_NORMAL, iq_mode = 0, isi; u32 ts_config = SX8_TSCONFIG_MODE_NORMAL, iq_mode = 0, isi, ts_mode = 0;
isi = p->stream_id; isi = p->stream_id;
if (isi != NO_STREAM_ID_FILTER) { if (isi != NO_STREAM_ID_FILTER) {
iq_mode = (isi & 0x30000000) >> 28; iq_mode = (isi & 0x30000000) >> 28;
ts_mode = (isi & 0x03000000) >> 24;
} }
state->mci.input->con = ts_mode << 8;
if (iq_mode) if (iq_mode)
ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ); ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ);
stop(fe); stop(fe);
@ -438,7 +469,7 @@ static int set_parameters(struct dvb_frontend *fe)
state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL; state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL;
} }
} else { } else {
stat = start_iq(fe, iq_mode & 1, 4, ts_config); stat = start_iq(fe, (isi >> 8) & 0xffff, 4, ts_config);
if (!stat) { if (!stat) {
state->iq_started = 1; state->iq_started = 1;
state->first_time_lock = 1; state->first_time_lock = 1;
@ -469,7 +500,7 @@ static int tune(struct dvb_frontend *fe, bool re_tune,
return 0; return 0;
} }
static int get_algo(struct dvb_frontend *fe) static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{ {
return DVBFE_ALGO_HW; return DVBFE_ALGO_HW;
} }
@ -509,10 +540,10 @@ static struct dvb_frontend_ops sx8_ops = {
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */ .xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
.info = { .info = {
.name = "DVB-S/S2X", .name = "DVB-S/S2X",
.frequency_min = 950000, .frequency_min_hz = 950000000,
.frequency_max = 2150000, .frequency_max_hz = 2150000000,
.frequency_stepsize = 0, .frequency_stepsize_hz = 0,
.frequency_tolerance = 0, .frequency_tolerance_hz = 0,
.symbol_rate_min = 100000, .symbol_rate_min = 100000,
.symbol_rate_max = 100000000, .symbol_rate_max = 100000000,
.caps = FE_CAN_INVERSION_AUTO | .caps = FE_CAN_INVERSION_AUTO |
@ -527,6 +558,7 @@ static struct dvb_frontend_ops sx8_ops = {
.release = release, .release = release,
.read_status = read_status, .read_status = read_status,
.set_input = set_input, .set_input = set_input,
.set_lna = set_lna,
.sleep = sleep, .sleep = sleep,
}; };

View File

@ -1,7 +1,8 @@
/* SPDX-License-Identifier: GPL-2.0 */
/* /*
* ddbridge.h: Digital Devices PCIe bridge driver * ddbridge.h: Digital Devices PCIe bridge driver
* *
* Copyright (C) 2010-2019 Digital Devices GmbH * Copyright (C) 2010-2017 Digital Devices GmbH
* Marcus Metzler <mocm@metzlerbros.de> * Marcus Metzler <mocm@metzlerbros.de>
* Ralph Metzler <rjkm@metzlerbros.de> * Ralph Metzler <rjkm@metzlerbros.de>
* *
@ -15,10 +16,8 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details. * GNU General Public License for more details.
* *
*
* You should have received a copy of the GNU General Public License * You should have received a copy of the GNU General Public License
* along with this program; if not, point your browser to * along with this program. If not, see <https://www.gnu.org/licenses/>.
* http://www.gnu.org/copyleft/gpl.html
*/ */
#ifndef _DDBRIDGE_H_ #ifndef _DDBRIDGE_H_
@ -61,22 +60,20 @@
#include <linux/mutex.h> #include <linux/mutex.h>
#include <asm/dma.h> #include <asm/dma.h>
#include <asm/irq.h> #include <asm/irq.h>
#include <linux/io.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/dvb/ca.h> #include <linux/dvb/ca.h>
#include <linux/socket.h> #include <linux/socket.h>
#include <linux/device.h> #include <linux/device.h>
#include <linux/io.h>
#include "dvb_netstream.h" #include "dvb_netstream.h"
#include "dmxdev.h" #include <media/dmxdev.h>
#include "dvbdev.h" #include <media/dvbdev.h>
#include "dvb_demux.h" #include <media/dvb_demux.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "dvb_ringbuffer.h" #include <media/dvb_ringbuffer.h>
#include "dvb_ca_en50221.h" #include <media/dvb_ca_en50221.h>
#include "dvb_net.h" #include <media/dvb_net.h>
#include "tda18271c2dd.h" #include "tda18271c2dd.h"
#include "stv6110x.h" #include "stv6110x.h"
@ -215,6 +212,9 @@ struct ddb_dma {
u32 ctrl; u32 ctrl;
u32 cbuf; u32 cbuf;
u32 coff; u32 coff;
u32 stall_count;
u32 packet_loss;
}; };
struct ddb_dvb { struct ddb_dvb {
@ -236,7 +236,7 @@ struct ddb_dvb {
enum fe_sec_tone_mode tone; enum fe_sec_tone_mode tone;
enum fe_sec_voltage voltage; enum fe_sec_voltage voltage;
int (*i2c_gate_ctrl)(struct dvb_frontend *, int); int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int val);
int (*set_voltage)(struct dvb_frontend *fe, int (*set_voltage)(struct dvb_frontend *fe,
enum fe_sec_voltage voltage); enum fe_sec_voltage voltage);
int (*set_input)(struct dvb_frontend *fe, int input); int (*set_input)(struct dvb_frontend *fe, int input);
@ -254,6 +254,7 @@ struct ddb_io {
struct ddb_port *port; struct ddb_port *port;
u32 nr; u32 nr;
u32 regs; u32 regs;
u32 con;
struct ddb_dma *dma; struct ddb_dma *dma;
struct ddb_io *redo; struct ddb_io *redo;
struct ddb_io *redi; struct ddb_io *redi;
@ -405,7 +406,7 @@ struct ddb_lnb {
}; };
struct ddb_irq { struct ddb_irq {
void (*handler)(void *); void (*handler)(void *data);
void *data; void *data;
}; };
@ -424,6 +425,8 @@ struct ddb_link {
int over_temperature_error; int over_temperature_error;
u8 temp_tab[11]; u8 temp_tab[11];
struct ddb_irq irq[256]; struct ddb_irq irq[256];
struct mci_base *mci_base;
}; };
struct ddb { struct ddb {
@ -450,7 +453,7 @@ struct ddb {
struct ddb_dma odma[DDB_MAX_OUTPUT]; struct ddb_dma odma[DDB_MAX_OUTPUT];
struct device *ddb_dev; struct device *ddb_dev;
u32 ddb_dev_users; atomic_t ddb_dev_users;
u32 nr; u32 nr;
u8 iobuf[1028]; u8 iobuf[1028];
@ -539,7 +542,7 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg);
int ddbridge_mod_init(struct ddb *dev); int ddbridge_mod_init(struct ddb *dev);
void ddbridge_mod_output_stop(struct ddb_output *output); void ddbridge_mod_output_stop(struct ddb_output *output);
int ddbridge_mod_output_start(struct ddb_output *output); int ddbridge_mod_output_start(struct ddb_output *output);
void ddbridge_mod_rate_handler(void *); void ddbridge_mod_rate_handler(void *data);
void ddb_device_destroy(struct ddb *dev); void ddb_device_destroy(struct ddb *dev);
void ddb_nsd_detach(struct ddb *dev); void ddb_nsd_detach(struct ddb *dev);

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,3 +1,4 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/* /*
* dvb_ca.c: generic DVB functions for EN50221 CAM interfaces * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces
* *
@ -11,18 +12,6 @@
* *
* Copyright (C) 1999-2002 Ralph Metzler * Copyright (C) 1999-2002 Ralph Metzler
* & Marcus Metzler for convergence integrated media GmbH * & 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 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
*/ */
#define pr_fmt(fmt) "dvb_ca_en50221: " fmt #define pr_fmt(fmt) "dvb_ca_en50221: " fmt
@ -31,10 +20,13 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
#include <linux/nospec.h>
#endif
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0))
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#else #else
@ -42,8 +34,8 @@
#endif #endif
#include <linux/kthread.h> #include <linux/kthread.h>
#include "dvb_ca_en50221.h" #include <media/dvb_ca_en50221.h>
#include "dvb_ringbuffer.h" #include <media/dvb_ringbuffer.h>
static int dvb_ca_en50221_debug; static int dvb_ca_en50221_debug;
@ -211,7 +203,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
* @hlen: Number of bytes in haystack. * @hlen: Number of bytes in haystack.
* @needle: Buffer to find. * @needle: Buffer to find.
* @nlen: Number of bytes in needle. * @nlen: Number of bytes in needle.
* @return Pointer into haystack needle was found at, or NULL if not found. * return: Pointer into haystack needle was found at, or NULL if not found.
*/ */
static char *findstr(char *haystack, int hlen, char *needle, int nlen) static char *findstr(char *haystack, int hlen, char *needle, int nlen)
{ {
@ -231,7 +223,7 @@ static char *findstr(char *haystack, int hlen, char *needle, int nlen)
/* ************************************************************************** */ /* ************************************************************************** */
/* EN50221 physical interface functions */ /* EN50221 physical interface functions */
/** /*
* dvb_ca_en50221_check_camstatus - Check CAM status. * dvb_ca_en50221_check_camstatus - Check CAM status.
*/ */
static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot) static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
@ -280,9 +272,9 @@ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot)
* @ca: CA instance. * @ca: CA instance.
* @slot: Slot on interface. * @slot: Slot on interface.
* @waitfor: Flags to wait for. * @waitfor: Flags to wait for.
* @timeout_ms: Timeout in milliseconds. * @timeout_hz: Timeout in milliseconds.
* *
* @return 0 on success, nonzero on error. * return: 0 on success, nonzero on error.
*/ */
static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
u8 waitfor, int timeout_hz) u8 waitfor, int timeout_hz)
@ -330,7 +322,7 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot,
* @ca: CA instance. * @ca: CA instance.
* @slot: Slot id. * @slot: Slot id.
* *
* @return 0 on success, nonzero on failure. * return: 0 on success, nonzero on failure.
*/ */
static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
{ {
@ -402,11 +394,11 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot)
* @ca: CA instance. * @ca: CA instance.
* @slot: Slot id. * @slot: Slot id.
* @address: Address to read from. Updated. * @address: Address to read from. Updated.
* @tupleType: Tuple id byte. Updated. * @tuple_type: Tuple id byte. Updated.
* @tupleLength: Tuple length. Updated. * @tuple_length: Tuple length. Updated.
* @tuple: Dest buffer for tuple (must be 256 bytes). Updated. * @tuple: Dest buffer for tuple (must be 256 bytes). Updated.
* *
* @return 0 on success, nonzero on error. * return: 0 on success, nonzero on error.
*/ */
static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot, static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
int *address, int *tuple_type, int *address, int *tuple_type,
@ -460,7 +452,7 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot,
* @ca: CA instance. * @ca: CA instance.
* @slot: Slot id. * @slot: Slot id.
* *
* @return 0 on success, <0 on failure. * return: 0 on success, <0 on failure.
*/ */
static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot)
{ {
@ -637,10 +629,11 @@ static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot)
* @ca: CA instance. * @ca: CA instance.
* @slot: Slot to read from. * @slot: Slot to read from.
* @ebuf: If non-NULL, the data will be written to this buffer. If NULL, * @ebuf: If non-NULL, the data will be written to this buffer. If NULL,
* the data will be added into the buffering system as a normal fragment. * the data will be added into the buffering system as a normal
* fragment.
* @ecount: Size of ebuf. Ignored if ebuf is NULL. * @ecount: Size of ebuf. Ignored if ebuf is NULL.
* *
* @return Number of bytes read, or < 0 on error * return: Number of bytes read, or < 0 on error
*/ */
static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot,
u8 *ebuf, int ecount) u8 *ebuf, int ecount)
@ -789,11 +782,11 @@ exit:
* *
* @ca: CA instance. * @ca: CA instance.
* @slot: Slot to write to. * @slot: Slot to write to.
* @ebuf: The data in this buffer is treated as a complete link-level packet to * @buf: The data in this buffer is treated as a complete link-level packet to
* be written. * be written.
* @count: Size of ebuf. * @bytes_write: Size of ebuf.
* *
* @return Number of bytes written, or < 0 on error. * return: Number of bytes written, or < 0 on error.
*/ */
static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot,
u8 *buf, int bytes_write) u8 *buf, int bytes_write)
@ -938,7 +931,7 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot)
/** /**
* dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred. * dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred.
* *
* @ca: CA instance. * @pubca: CA instance.
* @slot: Slot concerned. * @slot: Slot concerned.
* @change_type: One of the DVB_CA_CAMCHANGE_* values. * @change_type: One of the DVB_CA_CAMCHANGE_* values.
*/ */
@ -968,7 +961,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq);
/** /**
* dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred. * dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred.
* *
* @ca: CA instance. * @pubca: CA instance.
* @slot: Slot concerned. * @slot: Slot concerned.
*/ */
void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot) void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot)
@ -988,7 +981,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_camready_irq);
/** /**
* dvb_ca_en50221_frda_irq - An FR or DA IRQ has occurred. * dvb_ca_en50221_frda_irq - An FR or DA IRQ has occurred.
* *
* @ca: CA instance. * @pubca: CA instance.
* @slot: Slot concerned. * @slot: Slot concerned.
*/ */
void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot)
@ -1096,7 +1089,7 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca)
* *
* @ca: CA instance. * @ca: CA instance.
* @slot: Slot to process. * @slot: Slot to process.
* @return: 0 .. no change * return:: 0 .. no change
* 1 .. CAM state changed * 1 .. CAM state changed
*/ */
@ -1274,7 +1267,7 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca,
ca->pub->slot_ts_enable(ca->pub, slot); ca->pub->slot_ts_enable(ca->pub, slot);
sl->slot_state = DVB_CA_SLOTSTATE_RUNNING; sl->slot_state = DVB_CA_SLOTSTATE_RUNNING;
dvb_ca_en50221_thread_update_delay(ca); dvb_ca_en50221_thread_update_delay(ca);
pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", pr_info("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n",
ca->dvbdev->adapter->num); ca->dvbdev->adapter->num);
break; break;
@ -1317,7 +1310,7 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca,
mutex_unlock(&sl->slot_lock); mutex_unlock(&sl->slot_lock);
} }
/** /*
* Kernel thread which monitors CA slots for CAM changes, and performs data * Kernel thread which monitors CA slots for CAM changes, and performs data
* transfers. * transfers.
*/ */
@ -1357,12 +1350,11 @@ static int dvb_ca_en50221_thread(void *data)
* Real ioctl implementation. * Real ioctl implementation.
* NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them.
* *
* @inode: Inode concerned.
* @file: File concerned. * @file: File concerned.
* @cmd: IOCTL command. * @cmd: IOCTL command.
* @arg: Associated argument. * @parg: Associated argument.
* *
* @return 0 on success, <0 on error. * return: 0 on success, <0 on error.
*/ */
static int dvb_ca_en50221_io_do_ioctl(struct file *file, static int dvb_ca_en50221_io_do_ioctl(struct file *file,
unsigned int cmd, void *parg) unsigned int cmd, void *parg)
@ -1411,7 +1403,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
struct dvb_ca_slot *sl; struct dvb_ca_slot *sl;
slot = info->num; slot = info->num;
if ((slot > ca->slot_count) || (slot < 0)) { if ((slot >= ca->slot_count) || (slot < 0)) {
err = -EINVAL; err = -EINVAL;
goto out_unlock; goto out_unlock;
} }
@ -1441,12 +1433,11 @@ out_unlock:
/** /**
* Wrapper for ioctl implementation. * Wrapper for ioctl implementation.
* *
* @inode: Inode concerned.
* @file: File concerned. * @file: File concerned.
* @cmd: IOCTL command. * @cmd: IOCTL command.
* @arg: Associated argument. * @arg: Associated argument.
* *
* @return 0 on success, <0 on error. * return: 0 on success, <0 on error.
*/ */
static long dvb_ca_en50221_io_ioctl(struct file *file, static long dvb_ca_en50221_io_ioctl(struct file *file,
unsigned int cmd, unsigned long arg) unsigned int cmd, unsigned long arg)
@ -1462,7 +1453,7 @@ static long dvb_ca_en50221_io_ioctl(struct file *file,
* @count: Size of source buffer. * @count: Size of source buffer.
* @ppos: Position in file (ignored). * @ppos: Position in file (ignored).
* *
* @return Number of bytes read, or <0 on error. * return: Number of bytes read, or <0 on error.
*/ */
static ssize_t dvb_ca_en50221_io_write(struct file *file, static ssize_t dvb_ca_en50221_io_write(struct file *file,
const char __user *buf, size_t count, const char __user *buf, size_t count,
@ -1495,6 +1486,11 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
return -EFAULT; return -EFAULT;
buf += 2; buf += 2;
count -= 2; count -= 2;
if (slot >= ca->slot_count)
return -EINVAL;
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18))
slot = array_index_nospec(slot, ca->slot_count);
#endif
sl = &ca->slot_info[slot]; sl = &ca->slot_info[slot];
/* check if the slot is actually running */ /* check if the slot is actually running */
@ -1557,7 +1553,7 @@ exit:
return status; return status;
} }
/** /*
* Condition for waking up in dvb_ca_en50221_io_read_condition * Condition for waking up in dvb_ca_en50221_io_read_condition
*/ */
static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca,
@ -1614,7 +1610,7 @@ nextslot:
* @count: Size of destination buffer. * @count: Size of destination buffer.
* @ppos: Position in file (ignored). * @ppos: Position in file (ignored).
* *
* @return Number of bytes read, or <0 on error. * return: Number of bytes read, or <0 on error.
*/ */
static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
@ -1723,7 +1719,7 @@ exit:
* @inode: Inode concerned. * @inode: Inode concerned.
* @file: File concerned. * @file: File concerned.
* *
* @return 0 on success, <0 on failure. * return: 0 on success, <0 on failure.
*/ */
static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
{ {
@ -1773,7 +1769,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file)
* @inode: Inode concerned. * @inode: Inode concerned.
* @file: File concerned. * @file: File concerned.
* *
* @return 0 on success, <0 on failure. * return: 0 on success, <0 on failure.
*/ */
static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
{ {
@ -1802,30 +1798,33 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file)
* @file: File concerned. * @file: File concerned.
* @wait: poll wait table. * @wait: poll wait table.
* *
* @return Standard poll mask. * return: Standard poll mask.
*/ */
static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0))
typedef unsigned int __poll_t;
#define EPOLLIN POLLIN
#endif
static __poll_t dvb_ca_en50221_io_poll(struct file *file, poll_table *wait)
{ {
struct dvb_device *dvbdev = file->private_data; struct dvb_device *dvbdev = file->private_data;
struct dvb_ca_private *ca = dvbdev->priv; struct dvb_ca_private *ca = dvbdev->priv;
unsigned int mask = 0; __poll_t mask = 0;
int slot; int slot;
int result = 0; int result = 0;
dprintk("%s\n", __func__); dprintk("%s\n", __func__);
poll_wait(file, &ca->wait_queue, wait);
if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1)
mask |= POLLIN; mask |= EPOLLIN;
/* if there is something, return now */ /* if there is something, return now */
if (mask) if (mask)
return mask; return mask;
/* wait for something to happen */
poll_wait(file, &ca->wait_queue, wait);
if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1)
mask |= POLLIN; mask |= EPOLLIN;
return mask; return mask;
} }
@ -1859,11 +1858,11 @@ static const struct dvb_device dvbdev_ca = {
* Initialise a new DVB CA EN50221 interface device. * Initialise a new DVB CA EN50221 interface device.
* *
* @dvb_adapter: DVB adapter to attach the new CA device to. * @dvb_adapter: DVB adapter to attach the new CA device to.
* @ca: The dvb_ca instance. * @pubca: The dvb_ca instance.
* @flags: Flags describing the CA device (DVB_CA_FLAG_*). * @flags: Flags describing the CA device (DVB_CA_FLAG_*).
* @slot_count: Number of slots supported. * @slot_count: Number of slots supported.
* *
* @return 0 on success, nonzero on failure * return: 0 on success, nonzero on failure
*/ */
int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter,
struct dvb_ca_en50221 *pubca, int flags, int slot_count) struct dvb_ca_en50221 *pubca, int flags, int slot_count)
@ -1950,8 +1949,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_init);
/** /**
* Release a DVB CA EN50221 interface device. * Release a DVB CA EN50221 interface device.
* *
* @ca_dev: The dvb_device_t instance for the CA device. * @pubca: The associated dvb_ca instance.
* @ca: The associated dvb_ca instance.
*/ */
void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca)
{ {

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -41,7 +41,7 @@
#include <asm/div64.h> #include <asm/div64.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
#include "dvb_frontend.h" #include <media/dvb_frontend.h>
#include "mxl5xx.h" #include "mxl5xx.h"
#include "mxl5xx_regs.h" #include "mxl5xx_regs.h"
#include "mxl5xx_defs.h" #include "mxl5xx_defs.h"
@ -357,19 +357,6 @@ static int update_by_mnemonic(struct mxl *state,
return stat; return stat;
} }
#if 0
static void extract_from_mnemonic(u32 regAddr, u8 lsbPos, u8 width,
u32 *toAddr, u8 *toLsbPos, u8 *toWidth)
{
if (toAddr)
*toAddr = regAddr;
if (toLsbPos)
*toLsbPos = lsbPos;
if (toWidth)
*toWidth = width;
}
#endif
static int firmware_is_alive(struct mxl *state) static int firmware_is_alive(struct mxl *state)
{ {
u32 hb0, hb1; u32 hb0, hb1;
@ -379,10 +366,10 @@ static int firmware_is_alive(struct mxl *state)
msleep(20); msleep(20);
if (read_register(state, HYDRA_HEAR_BEAT, &hb1)) if (read_register(state, HYDRA_HEAR_BEAT, &hb1))
return 0; return 0;
if (hb1 == hb0) if (hb1 == hb0) {
pr_warn("mxl5xx: Hydra FW not running!\n");
return 0; return 0;
}
pr_info("mxl5xx: Hydra FW alive. Hail!\n");
return 1; return 1;
} }
@ -405,7 +392,7 @@ static void release(struct dvb_frontend *fe)
kfree(state); kfree(state);
} }
static int get_algo(struct dvb_frontend *fe) static enum dvbfe_algo get_algo(struct dvb_frontend *fe)
{ {
return DVBFE_ALGO_HW; return DVBFE_ALGO_HW;
} }
@ -799,6 +786,7 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties
default: default:
break; break;
} }
/* fallthrough */
case SYS_DVBS: case SYS_DVBS:
switch ((MXL_HYDRA_MODULATION_E) switch ((MXL_HYDRA_MODULATION_E)
regData[DMD_MODULATION_SCHEME_ADDR]) { regData[DMD_MODULATION_SCHEME_ADDR]) {
@ -846,10 +834,10 @@ static struct dvb_frontend_ops mxl_ops = {
.xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */ .xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */
.info = { .info = {
.name = "MXL5XX", .name = "MXL5XX",
.frequency_min = 300000, .frequency_min_hz = 300000000,
.frequency_max = 2350000, .frequency_max_hz = 2350000000,
.frequency_stepsize = 0, .frequency_stepsize_hz = 0,
.frequency_tolerance = 0, .frequency_tolerance_hz = 0,
.symbol_rate_min = 1000000, .symbol_rate_min = 1000000,
.symbol_rate_max = 45000000, .symbol_rate_max = 45000000,
.caps = FE_CAN_INVERSION_AUTO | .caps = FE_CAN_INVERSION_AUTO |

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,5 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
/* /*
* audio.h * audio.h - DEPRECATED MPEG-TS audio decoder API
*
* NOTE: should not be used on future drivers
* *
* Copyright (C) 2000 Ralph Metzler <ralph@convergence.de> * Copyright (C) 2000 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de> * & Marcus Metzler <marcus@convergence.de>
@ -51,7 +54,7 @@ typedef enum {
typedef struct audio_mixer { typedef struct audio_mixer {
unsigned int volume_left; unsigned int volume_left;
unsigned int volume_right; unsigned int volume_right;
// what else do we need? bass, pass-through, ... /* what else do we need? bass, pass-through, ... */
} audio_mixer_t; } audio_mixer_t;
@ -66,27 +69,6 @@ typedef struct audio_status {
} audio_status_t; /* separate decoder hardware */ } audio_status_t; /* separate decoder hardware */
typedef
struct audio_karaoke { /* if Vocal1 or Vocal2 are non-zero, they get mixed */
int vocal1; /* into left and right t at 70% each */
int vocal2; /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets*/
int melody; /* mixed into the left channel and */
/* Vocal2 into the right channel at 100% each. */
/* if Melody is non-zero, the melody channel gets mixed*/
} audio_karaoke_t; /* into left and right */
typedef __u16 audio_attributes_t;
/* bits: descr. */
/* 15-13 audio coding mode (0=ac3, 2=mpeg1, 3=mpeg2ext, 4=LPCM, 6=DTS, */
/* 12 multichannel extension */
/* 11-10 audio type (0=not spec, 1=language included) */
/* 9- 8 audio application mode (0=not spec, 1=karaoke, 2=surround) */
/* 7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit, */
/* 5- 4 Sample frequency fs (0=48kHz, 1=96kHz) */
/* 2- 0 number of audio channels (n+1 channels) */
/* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */ /* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */
#define AUDIO_CAP_DTS 1 #define AUDIO_CAP_DTS 1
#define AUDIO_CAP_LPCM 2 #define AUDIO_CAP_LPCM 2
@ -114,22 +96,6 @@ typedef __u16 audio_attributes_t;
#define AUDIO_SET_ID _IO('o', 13) #define AUDIO_SET_ID _IO('o', 13)
#define AUDIO_SET_MIXER _IOW('o', 14, audio_mixer_t) #define AUDIO_SET_MIXER _IOW('o', 14, audio_mixer_t)
#define AUDIO_SET_STREAMTYPE _IO('o', 15) #define AUDIO_SET_STREAMTYPE _IO('o', 15)
#define AUDIO_SET_EXT_ID _IO('o', 16)
#define AUDIO_SET_ATTRIBUTES _IOW('o', 17, audio_attributes_t)
#define AUDIO_SET_KARAOKE _IOW('o', 18, audio_karaoke_t)
/**
* AUDIO_GET_PTS
*
* Read the 33 bit presentation time stamp as defined
* in ITU T-REC-H.222.0 / ISO/IEC 13818-1.
*
* The PTS should belong to the currently played
* frame if possible, but may also be a value close to it
* like the PTS of the last decoded frame or the last PTS
* extracted by the PES parser.
*/
#define AUDIO_GET_PTS _IOR('o', 19, __u64)
#define AUDIO_BILINGUAL_CHANNEL_SELECT _IO('o', 20) #define AUDIO_BILINGUAL_CHANNEL_SELECT _IO('o', 20)
#endif /* _DVBAUDIO_H_ */ #endif /* _DVBAUDIO_H_ */

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
/* /*
* ca.h * ca.h
* *

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
/* /*
* dmx.h * dmx.h
* *
@ -210,6 +211,96 @@ struct dmx_stc {
__u64 stc; __u64 stc;
}; };
/**
* enum dmx_buffer_flags - DMX memory-mapped buffer flags
*
* @DMX_BUFFER_FLAG_HAD_CRC32_DISCARD:
* Indicates that the Kernel discarded one or more frames due to wrong
* CRC32 checksum.
* @DMX_BUFFER_FLAG_TEI:
* Indicates that the Kernel has detected a Transport Error indicator
* (TEI) on a filtered pid.
* @DMX_BUFFER_PKT_COUNTER_MISMATCH:
* Indicates that the Kernel has detected a packet counter mismatch
* on a filtered pid.
* @DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED:
* Indicates that the Kernel has detected one or more frame discontinuity.
* @DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR:
* Received at least one packet with a frame discontinuity indicator.
*/
enum dmx_buffer_flags {
DMX_BUFFER_FLAG_HAD_CRC32_DISCARD = 1 << 0,
DMX_BUFFER_FLAG_TEI = 1 << 1,
DMX_BUFFER_PKT_COUNTER_MISMATCH = 1 << 2,
DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED = 1 << 3,
DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR = 1 << 4,
};
/**
* struct dmx_buffer - dmx buffer info
*
* @index: id number of the buffer
* @bytesused: number of bytes occupied by data in the buffer (payload);
* @offset: for buffers with memory == DMX_MEMORY_MMAP;
* offset from the start of the device memory for this plane,
* (or a "cookie" that should be passed to mmap() as offset)
* @length: size in bytes of the buffer
* @flags: bit array of buffer flags as defined by &enum dmx_buffer_flags.
* Filled only at &DMX_DQBUF.
* @count: monotonic counter for filled buffers. Helps to identify
* data stream loses. Filled only at &DMX_DQBUF.
*
* Contains data exchanged by application and driver using one of the streaming
* I/O methods.
*
* Please notice that, for &DMX_QBUF, only @index should be filled.
* On &DMX_DQBUF calls, all fields will be filled by the Kernel.
*/
struct dmx_buffer {
__u32 index;
__u32 bytesused;
__u32 offset;
__u32 length;
__u32 flags;
__u32 count;
};
/**
* struct dmx_requestbuffers - request dmx buffer information
*
* @count: number of requested buffers,
* @size: size in bytes of the requested buffer
*
* Contains data used for requesting a dmx buffer.
* All reserved fields must be set to zero.
*/
struct dmx_requestbuffers {
__u32 count;
__u32 size;
};
/**
* struct dmx_exportbuffer - export of dmx buffer as DMABUF file descriptor
*
* @index: id number of the buffer
* @flags: flags for newly created file, currently only O_CLOEXEC is
* supported, refer to manual of open syscall for more details
* @fd: file descriptor associated with DMABUF (set by driver)
*
* Contains data used for exporting a dmx buffer as DMABUF file descriptor.
* The buffer is identified by a 'cookie' returned by DMX_QUERYBUF
* (identical to the cookie used to mmap() the buffer to userspace). All
* reserved fields must be set to zero. The field reserved0 is expected to
* become a structure 'type' allowing an alternative layout of the structure
* content. Therefore this field should not be used for any other extensions.
*/
struct dmx_exportbuffer {
__u32 index;
__u32 flags;
__s32 fd;
};
#define DMX_START _IO('o', 41) #define DMX_START _IO('o', 41)
#define DMX_STOP _IO('o', 42) #define DMX_STOP _IO('o', 42)
#define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params) #define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params)
@ -230,4 +321,10 @@ typedef struct dmx_filter dmx_filter_t;
#endif #endif
#endif /* _UAPI_DVBDMX_H_ */ #define DMX_REQBUFS _IOWR('o', 60, struct dmx_requestbuffers)
#define DMX_QUERYBUF _IOWR('o', 61, struct dmx_buffer)
#define DMX_EXPBUF _IOWR('o', 62, struct dmx_exportbuffer)
#define DMX_QBUF _IOWR('o', 63, struct dmx_buffer)
#define DMX_DQBUF _IOWR('o', 64, struct dmx_buffer)
#endif /* _DVBDMX_H_ */

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
/* /*
* frontend.h * frontend.h
* *
@ -769,16 +770,15 @@ enum fecap_scale_params {
/** /**
* struct dtv_stats - Used for reading a DTV status property * struct dtv_stats - Used for reading a DTV status property
* *
* @scale: Filled with enum fecap_scale_params - the scale * @scale:
* in usage for that parameter * Filled with enum fecap_scale_params - the scale in usage
* for that parameter
* *
* The ``{unnamed_union}`` may have either one of the values below: * @svalue:
*
* %svalue
* integer value of the measure, for %FE_SCALE_DECIBEL, * integer value of the measure, for %FE_SCALE_DECIBEL,
* used for dB measures. The unit is 0.001 dB. * used for dB measures. The unit is 0.001 dB.
* *
* %uvalue * @uvalue:
* unsigned integer value of the measure, used when @scale is * unsigned integer value of the measure, used when @scale is
* either %FE_SCALE_RELATIVE or %FE_SCALE_COUNTER. * either %FE_SCALE_RELATIVE or %FE_SCALE_COUNTER.
* *
@ -844,16 +844,16 @@ struct dtv_fe_stats {
* @cmd: Digital TV command. * @cmd: Digital TV command.
* @reserved: Not used. * @reserved: Not used.
* @u: Union with the values for the command. * @u: Union with the values for the command.
* @result: Result of the command set (currently unused). * @u.data: A unsigned 32 bits integer with command value.
* @u.buffer: Struct to store bigger properties.
* Currently unused.
* @u.buffer.data: an unsigned 32-bits array.
* @u.buffer.len: number of elements of the buffer.
* @u.buffer.reserved1: Reserved.
* @u.buffer.reserved2: Reserved.
* @u.st: a &struct dtv_fe_stats array of statistics.
* @result: Currently unused.
* *
* The @u union may have either one of the values below:
*
* %data
* an unsigned 32-bits number.
* %st
* a &struct dtv_fe_stats array of statistics.
* %buffer
* a buffer of up to 32 characters (currently unused).
*/ */
struct dtv_property { struct dtv_property {
__u32 cmd; __u32 cmd;

View File

@ -38,9 +38,14 @@ struct dvb_mod_channel_params {
enum mod_output_rate { enum mod_output_rate {
SYS_DVBT_6 = 0, SYS_DVBT_6 = 0,
SYS_DVBT_7, SYS_DVBT_7 = 1,
SYS_DVBT_8, SYS_DVBT_8 = 2,
SYS_DVBC_6900 = 8,
SYS_ISDBT_6 = 16, SYS_ISDBT_6 = 16,
SYS_J83B_64_6 = 24,
SYS_J83B_256_6 = 25,
SYS_DVBS2_22 = 32,
SYS_DVBS2_24 = 33,
}; };

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
/* /*
* net.h * net.h
* *

View File

@ -1,5 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
/* /*
* osd.h * osd.h - DEPRECATED On Screen Display API
*
* NOTE: should not be used on future drivers
* *
* Copyright (C) 2001 Ralph Metzler <ralph@convergence.de> * Copyright (C) 2001 Ralph Metzler <ralph@convergence.de>
* & Marcus Metzler <marcus@convergence.de> * & Marcus Metzler <marcus@convergence.de>
@ -26,79 +29,109 @@
#include <linux/compiler.h> #include <linux/compiler.h>
#ifndef __user
#define __user
#endif
typedef enum { typedef enum {
// All functions return -2 on "not open" /* All functions return -2 on "not open" */
OSD_Close=1, // () OSD_Close = 1, /* () */
// Disables OSD and releases the buffers /*
// returns 0 on success * Disables OSD and releases the buffers
OSD_Open, // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) * returns 0 on success
// Opens OSD with this size and bit depth */
// returns 0 on success, -1 on DRAM allocation error, -2 on "already open" OSD_Open, /* (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) */
OSD_Show, // () /*
// enables OSD mode * Opens OSD with this size and bit depth
// returns 0 on success * returns 0 on success, -1 on DRAM allocation error, -2 on "already open"
OSD_Hide, // () */
// disables OSD mode OSD_Show, /* () */
// returns 0 on success /*
OSD_Clear, // () * enables OSD mode
// Sets all pixel to color 0 * returns 0 on success
// returns 0 on success */
OSD_Fill, // (color) OSD_Hide, /* () */
// Sets all pixel to color <col> /*
// returns 0 on success * disables OSD mode
OSD_SetColor, // (color,R{x0},G{y0},B{x1},opacity{y1}) * returns 0 on success
// set palette entry <num> to <r,g,b>, <mix> and <trans> apply */
// R,G,B: 0..255 OSD_Clear, /* () */
// R=Red, G=Green, B=Blue /*
// opacity=0: pixel opacity 0% (only video pixel shows) * Sets all pixel to color 0
// opacity=1..254: pixel opacity as specified in header * returns 0 on success
// opacity=255: pixel opacity 100% (only OSD pixel shows) */
// returns 0 on success, -1 on error OSD_Fill, /* (color) */
OSD_SetPalette, // (firstcolor{color},lastcolor{x0},data) /*
// Set a number of entries in the palette * Sets all pixel to color <col>
// sets the entries "firstcolor" through "lastcolor" from the array "data" * returns 0 on success
// data has 4 byte for each color: */
// R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel OSD_SetColor, /* (color,R{x0},G{y0},B{x1},opacity{y1}) */
OSD_SetTrans, // (transparency{color}) /*
// Sets transparency of mixed pixel (0..15) * set palette entry <num> to <r,g,b>, <mix> and <trans> apply
// returns 0 on success * R,G,B: 0..255
OSD_SetPixel, // (x0,y0,color) * R=Red, G=Green, B=Blue
// sets pixel <x>,<y> to color number <col> * opacity=0: pixel opacity 0% (only video pixel shows)
// returns 0 on success, -1 on error * opacity=1..254: pixel opacity as specified in header
OSD_GetPixel, // (x0,y0) * opacity=255: pixel opacity 100% (only OSD pixel shows)
// returns color number of pixel <x>,<y>, or -1 * returns 0 on success, -1 on error
OSD_SetRow, // (x0,y0,x1,data) */
// fills pixels x0,y through x1,y with the content of data[] OSD_SetPalette, /* (firstcolor{color},lastcolor{x0},data) */
// returns 0 on success, -1 on clipping all pixel (no pixel drawn) /*
OSD_SetBlock, // (x0,y0,x1,y1,increment{color},data) * Set a number of entries in the palette
// fills pixels x0,y0 through x1,y1 with the content of data[] * sets the entries "firstcolor" through "lastcolor" from the array "data"
// inc contains the width of one line in the data block, * data has 4 byte for each color:
// inc<=0 uses blockwidth as linewidth * R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel
// returns 0 on success, -1 on clipping all pixel */
OSD_FillRow, // (x0,y0,x1,color) OSD_SetTrans, /* (transparency{color}) */
// fills pixels x0,y through x1,y with the color <col> /*
// returns 0 on success, -1 on clipping all pixel * Sets transparency of mixed pixel (0..15)
OSD_FillBlock, // (x0,y0,x1,y1,color) * returns 0 on success
// fills pixels x0,y0 through x1,y1 with the color <col> */
// returns 0 on success, -1 on clipping all pixel OSD_SetPixel, /* (x0,y0,color) */
OSD_Line, // (x0,y0,x1,y1,color) /*
// draw a line from x0,y0 to x1,y1 with the color <col> * sets pixel <x>,<y> to color number <col>
// returns 0 on success * returns 0 on success, -1 on error
OSD_Query, // (x0,y0,x1,y1,xasp{color}}), yasp=11 */
// fills parameters with the picture dimensions and the pixel aspect ratio OSD_GetPixel, /* (x0,y0) */
// returns 0 on success /* returns color number of pixel <x>,<y>, or -1 */
OSD_Test, // () OSD_SetRow, /* (x0,y0,x1,data) */
// draws a test picture. for debugging purposes only /*
// returns 0 on success * fills pixels x0,y through x1,y with the content of data[]
// TODO: remove "test" in final version * returns 0 on success, -1 on clipping all pixel (no pixel drawn)
OSD_Text, // (x0,y0,size,color,text) */
OSD_SetWindow, // (x0) set window with number 0<x0<8 as current OSD_SetBlock, /* (x0,y0,x1,y1,increment{color},data) */
OSD_MoveWindow, // move current window to (x0, y0) /*
OSD_OpenRaw, // Open other types of OSD windows * fills pixels x0,y0 through x1,y1 with the content of data[]
* inc contains the width of one line in the data block,
* inc<=0 uses blockwidth as linewidth
* returns 0 on success, -1 on clipping all pixel
*/
OSD_FillRow, /* (x0,y0,x1,color) */
/*
* fills pixels x0,y through x1,y with the color <col>
* returns 0 on success, -1 on clipping all pixel
*/
OSD_FillBlock, /* (x0,y0,x1,y1,color) */
/*
* fills pixels x0,y0 through x1,y1 with the color <col>
* returns 0 on success, -1 on clipping all pixel
*/
OSD_Line, /* (x0,y0,x1,y1,color) */
/*
* draw a line from x0,y0 to x1,y1 with the color <col>
* returns 0 on success
*/
OSD_Query, /* (x0,y0,x1,y1,xasp{color}}), yasp=11 */
/*
* fills parameters with the picture dimensions and the pixel aspect ratio
* returns 0 on success
*/
OSD_Test, /* () */
/*
* draws a test picture. for debugging purposes only
* returns 0 on success
* TODO: remove "test" in final version
*/
OSD_Text, /* (x0,y0,size,color,text) */
OSD_SetWindow, /* (x0) set window with number 0<x0<8 as current */
OSD_MoveWindow, /* move current window to (x0, y0) */
OSD_OpenRaw, /* Open other types of OSD windows */
} OSD_Command; } OSD_Command;
typedef struct osd_cmd_s { typedef struct osd_cmd_s {

View File

@ -1,3 +1,4 @@
/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
/* /*
* version.h * version.h
* *

View File

@ -1,5 +1,8 @@
/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */
/* /*
* video.h * video.h - DEPRECATED MPEG-TS video decoder API
*
* NOTE: should not be used on future drivers
* *
* Copyright (C) 2000 Marcus Metzler <marcus@convergence.de> * Copyright (C) 2000 Marcus Metzler <marcus@convergence.de>
* & Ralph Metzler <ralph@convergence.de> * & Ralph Metzler <ralph@convergence.de>
@ -29,10 +32,6 @@
#include <time.h> #include <time.h>
#endif #endif
#ifndef __user
#define __user
#endif
typedef enum { typedef enum {
VIDEO_FORMAT_4_3, /* Select 4:3 format */ VIDEO_FORMAT_4_3, /* Select 4:3 format */
VIDEO_FORMAT_16_9, /* Select 16:9 format. */ VIDEO_FORMAT_16_9, /* Select 16:9 format. */
@ -40,18 +39,6 @@ typedef enum {
} video_format_t; } video_format_t;
typedef enum {
VIDEO_SYSTEM_PAL,
VIDEO_SYSTEM_NTSC,
VIDEO_SYSTEM_PALN,
VIDEO_SYSTEM_PALNc,
VIDEO_SYSTEM_PALM,
VIDEO_SYSTEM_NTSC60,
VIDEO_SYSTEM_PAL60,
VIDEO_SYSTEM_PALM60
} video_system_t;
typedef enum { typedef enum {
VIDEO_PAN_SCAN, /* use pan and scan format */ VIDEO_PAN_SCAN, /* use pan and scan format */
VIDEO_LETTER_BOX, /* use letterbox format */ VIDEO_LETTER_BOX, /* use letterbox format */
@ -86,11 +73,11 @@ typedef enum {
#define VIDEO_CMD_CONTINUE (3) #define VIDEO_CMD_CONTINUE (3)
/* Flags for VIDEO_CMD_FREEZE */ /* Flags for VIDEO_CMD_FREEZE */
#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0) #define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0)
/* Flags for VIDEO_CMD_STOP */ /* Flags for VIDEO_CMD_STOP */
#define VIDEO_CMD_STOP_TO_BLACK (1 << 0) #define VIDEO_CMD_STOP_TO_BLACK (1 << 0)
#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1) #define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1)
/* Play input formats: */ /* Play input formats: */
/* The decoder has no special format requirements */ /* The decoder has no special format requirements */
@ -127,8 +114,8 @@ struct video_command {
/* FIELD_UNKNOWN can be used if the hardware does not know whether /* FIELD_UNKNOWN can be used if the hardware does not know whether
the Vsync is for an odd, even or progressive (i.e. non-interlaced) the Vsync is for an odd, even or progressive (i.e. non-interlaced)
field. */ field. */
#define VIDEO_VSYNC_FIELD_UNKNOWN (0) #define VIDEO_VSYNC_FIELD_UNKNOWN (0)
#define VIDEO_VSYNC_FIELD_ODD (1) #define VIDEO_VSYNC_FIELD_ODD (1)
#define VIDEO_VSYNC_FIELD_EVEN (2) #define VIDEO_VSYNC_FIELD_EVEN (2)
#define VIDEO_VSYNC_FIELD_PROGRESSIVE (3) #define VIDEO_VSYNC_FIELD_PROGRESSIVE (3)
@ -136,8 +123,8 @@ struct video_event {
__s32 type; __s32 type;
#define VIDEO_EVENT_SIZE_CHANGED 1 #define VIDEO_EVENT_SIZE_CHANGED 1
#define VIDEO_EVENT_FRAME_RATE_CHANGED 2 #define VIDEO_EVENT_FRAME_RATE_CHANGED 2
#define VIDEO_EVENT_DECODER_STOPPED 3 #define VIDEO_EVENT_DECODER_STOPPED 3
#define VIDEO_EVENT_VSYNC 4 #define VIDEO_EVENT_VSYNC 4
/* unused, make sure to use atomic time for y2038 if it ever gets used */ /* unused, make sure to use atomic time for y2038 if it ever gets used */
long timestamp; long timestamp;
union { union {
@ -163,44 +150,6 @@ struct video_still_picture {
}; };
typedef
struct video_highlight {
int active; /* 1=show highlight, 0=hide highlight */
__u8 contrast1; /* 7- 4 Pattern pixel contrast */
/* 3- 0 Background pixel contrast */
__u8 contrast2; /* 7- 4 Emphasis pixel-2 contrast */
/* 3- 0 Emphasis pixel-1 contrast */
__u8 color1; /* 7- 4 Pattern pixel color */
/* 3- 0 Background pixel color */
__u8 color2; /* 7- 4 Emphasis pixel-2 color */
/* 3- 0 Emphasis pixel-1 color */
__u32 ypos; /* 23-22 auto action mode */
/* 21-12 start y */
/* 9- 0 end y */
__u32 xpos; /* 23-22 button color number */
/* 21-12 start x */
/* 9- 0 end x */
} video_highlight_t;
typedef struct video_spu {
int active;
int stream_id;
} video_spu_t;
typedef struct video_spu_palette { /* SPU Palette information */
int length;
__u8 __user *palette;
} video_spu_palette_t;
typedef struct video_navi_pack {
int length; /* 0 ... 1024 */
__u8 data[1024];
} video_navi_pack_t;
typedef __u16 video_attributes_t; typedef __u16 video_attributes_t;
/* bits: descr. */ /* bits: descr. */
/* 15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) */ /* 15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) */
@ -245,17 +194,9 @@ typedef __u16 video_attributes_t;
#define VIDEO_SLOWMOTION _IO('o', 32) #define VIDEO_SLOWMOTION _IO('o', 32)
#define VIDEO_GET_CAPABILITIES _IOR('o', 33, unsigned int) #define VIDEO_GET_CAPABILITIES _IOR('o', 33, unsigned int)
#define VIDEO_CLEAR_BUFFER _IO('o', 34) #define VIDEO_CLEAR_BUFFER _IO('o', 34)
#define VIDEO_SET_ID _IO('o', 35)
#define VIDEO_SET_STREAMTYPE _IO('o', 36) #define VIDEO_SET_STREAMTYPE _IO('o', 36)
#define VIDEO_SET_FORMAT _IO('o', 37) #define VIDEO_SET_FORMAT _IO('o', 37)
#define VIDEO_SET_SYSTEM _IO('o', 38)
#define VIDEO_SET_HIGHLIGHT _IOW('o', 39, video_highlight_t)
#define VIDEO_SET_SPU _IOW('o', 50, video_spu_t)
#define VIDEO_SET_SPU_PALETTE _IOW('o', 51, video_spu_palette_t)
#define VIDEO_GET_NAVI _IOR('o', 52, video_navi_pack_t)
#define VIDEO_SET_ATTRIBUTES _IO('o', 53)
#define VIDEO_GET_SIZE _IOR('o', 55, video_size_t) #define VIDEO_GET_SIZE _IOR('o', 55, video_size_t)
#define VIDEO_GET_FRAME_RATE _IOR('o', 56, unsigned int)
/** /**
* VIDEO_GET_PTS * VIDEO_GET_PTS
@ -271,9 +212,9 @@ typedef __u16 video_attributes_t;
#define VIDEO_GET_PTS _IOR('o', 57, __u64) #define VIDEO_GET_PTS _IOR('o', 57, __u64)
/* Read the number of displayed frames since the decoder was started */ /* Read the number of displayed frames since the decoder was started */
#define VIDEO_GET_FRAME_COUNT _IOR('o', 58, __u64) #define VIDEO_GET_FRAME_COUNT _IOR('o', 58, __u64)
#define VIDEO_COMMAND _IOWR('o', 59, struct video_command) #define VIDEO_COMMAND _IOWR('o', 59, struct video_command)
#define VIDEO_TRY_COMMAND _IOWR('o', 60, struct video_command) #define VIDEO_TRY_COMMAND _IOWR('o', 60, struct video_command)
#endif /* _UAPI_DVBVIDEO_H_ */ #endif /* _UAPI_DVBVIDEO_H_ */

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -13,10 +13,10 @@ install: all
$(CC) $(CFLAGS) -fPIC -c $< $(CC) $(CFLAGS) -fPIC -c $<
dddvb_test: dddvb_test.o dddvb_test: dddvb_test.o
$(CC) -o dddvb_test $< -L ./src -l dddvb -l pthread -l dvben50221 -l dvbapi -l ucsi $(CC) -o dddvb_test $< -L ./src -l dddvb -l pthread -l dvben50221 -l dvbapi -l ucsi
ddzap: ddzap.o ddzap: ddzap.o
$(CC) -o ddzap $< -L ./src -l dddvb -l pthread -l dvben50221 -l dvbapi -l ucsi $(CC) -o ddzap $< -L ./src -l dddvb -l pthread -l dvben50221 -l dvbapi -l ucsi -lm
clean: clean:
make -C ./src clean make -C ./src clean

View File

@ -10,7 +10,248 @@
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h> #include <stdlib.h>
#include <stdint.h> #include <stdint.h>
#include <math.h>
#include <time.h>
char line_start[16] = "";
char line_end[16] = "\r";
uint32_t cc_errors = 0;
uint32_t packets = 0;
uint32_t payload_packets = 0;
uint32_t packet_errors = 0;
uint8_t cc[8192] = { 0 };
enum { IQ_RED=1, IQ_GREE, IQ_BLUE , IQ_EVIL, IQ_LOG_RED, IQ_LOG_GREEN, IQ_LOG_BLUE , IQ_LOG_EVIL , IQ_TEST, };
typedef struct pamdata_
{
unsigned char *data_points;
uint64_t *data;
int col;
} pamdata;
int init_pamdata(pamdata *iq,int color)
{
iq->col = 0;
if (!( iq->data=(uint64_t *) malloc(sizeof(uint64_t) *256*256)))
{
fprintf(stderr,"not enough memory\n");
return -1;
}
memset(iq->data,0,256*256*sizeof(uint64_t));
if (!( iq->data_points=(unsigned char *) malloc(sizeof(unsigned char) *
256*256*3)))
{
fprintf(stderr,"not enough memory\n");
return -1;
}
memset(iq->data_points,0,256*256*3*sizeof(char));
iq->col = color;
return 0;
}
static long getutime(){
struct timespec t0;
clock_gettime(CLOCK_MONOTONIC_RAW,&t0);
return t0.tv_sec * (int)1e9 + t0.tv_nsec;
}
void pam_coordinate_axes(pamdata *iq, unsigned char r,
unsigned char g, unsigned char b){
int i;
for (i = 0; i < 256*3; i+=3){
// coordinate axes
int xr = i + 256*128*3;
int yr =128*3 + i*256;
iq->data_points[xr] = r;
iq->data_points[yr] = r;
iq->data_points[xr+1] = g;
iq->data_points[yr+1] = g;
iq->data_points[xr+2] = b;
iq->data_points[yr+2] = b;
}
}
void pam_data_convert(pamdata *iq ,uint64_t maxd)
{
int i;
uint64_t m = 255*maxd;
double lm = log((double)m);
memset(iq->data_points,0,256*256*3*sizeof(char));
for (i = 0; i < 256*256*3; i+=3){
// IQ data plot
int r = i;
int g = i+1;
int b = i+2;
uint64_t odata = iq->data[i/3];
uint64_t data = 255*iq->data[i/3];
double lod = log((double)odata);
double q = lod/lm;
if (data){
switch (iq->col){
case IQ_LOG_EVIL:
if ( q < 0.25){
iq->data_points[b] = (int)(1024.0*q);
} else {
if (q >0.5) iq->data_points[g] = (int)(255.0*q);
else
iq->data_points[r] = (int)(512.0*q);
}
break;
case IQ_LOG_RED:
iq->data_points[r] = (int)(255.0*q)&0xff;
break;
case IQ_LOG_GREEN:
iq->data_points[g] = (int)(255.0*q)&0xff;
break;
case IQ_LOG_BLUE:
iq->data_points[b] = (int)(255.0*q)&0xff;
break;
case IQ_EVIL:
if (data < m/4){
iq->data_points[b] = ((4*data)/maxd)&0xff;
} else {
if (data >m/2) iq->data_points[g] = (data/maxd)&0xff;
else iq->data_points[r] = (2*data/maxd)&0xff;
}
break;
case IQ_TEST:
if (data < m/4){
iq->data_points[b] = ((4*data)/maxd)&0xff;
iq->data_points[g] = ((4*data)/maxd)&0xff;
} else {
if (data >m/2) {
iq->data_points[g] = (data/maxd)&0xff;
} else {
iq->data_points[g] = (2*data/maxd)&0xff;
iq->data_points[r] = (2*data/maxd)&0xff;
}
}
break;
case IQ_RED:
iq->data_points[r] = (data/maxd)&0xff;
break;
case IQ_BLUE:
iq->data_points[b] = (data/maxd)&0xff;
break;
default:
case IQ_GREE:
iq->data_points[g] = (data/maxd)&0xff;
break;
}
}
}
}
#define TS_SIZE 188
#define BSIZE 100*TS_SIZE
#define DTIME 40000000ULL
void pam_read_data (int fdin, pamdata *iq)
{
int8_t buf[BSIZE];
int i,j;
long t0;
long t1;
uint64_t maxd = 0;
t0 = getutime();
t1 = t0;
while ((t1 - t0) < DTIME){
int re =0;
if ((re=read(fdin,(char *)buf, BSIZE)) < 0){
return;
}
for (i=0; i < re; i+=TS_SIZE){
for (j=4; j<TS_SIZE; j+=2){
uint8_t ix = buf[i+j]+128;
uint8_t qy = 128-buf[i+j+1];
iq->data[ix|(qy<<8)] += 1;
uint64_t c = iq->data[ix|(qy<<8)];
if ( c > maxd) maxd = c;
}
}
t1 = getutime();
}
pam_data_convert(iq, maxd);
pam_coordinate_axes(iq, 255,255 ,0);
memset(iq->data,0,256*256*sizeof(uint64_t));
}
void pam_write (int fd, pamdata *iq){
char *HEAD="P7\nWIDTH 256\nHEIGHT 256\nDEPTH 3\nMAXVAL 255\nTUPLTYPE RGB\nENDHDR\n";
int headlen = strlen(HEAD);
int we=0;
we=write(fd,HEAD,headlen);
we=write(fd,iq->data_points,256*256*3);
memset(iq->data_points,0,256*256*3*sizeof(char));
}
void proc_ts(int i, uint8_t *buf)
{
uint16_t pid=0x1fff&((buf[1]<<8)|buf[2]);
uint8_t ccin = buf[3] & 0x1F;
if (buf[0] == 0x47 && (buf[1] & 0x80) == 0) {
if( pid != 8191 ) {
if (ccin & 0x10) {
if ( cc[pid]) {
// TODO: 1 repetition allowed
if( ( ccin & 0x10 ) != 0 && (((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) )
cc_errors += 1;
}
cc[pid] = ccin;
}
payload_packets += 1;
}
} else
packet_errors += 1;
if( (packets & 0x3FFF ) == 0)
{
printf("%s Packets: %12u non null %12u, errors: %12u, CC errors: %12u%s", line_start, packets, payload_packets, packet_errors, cc_errors, line_end);
fflush(stdout);
}
packets += 1;
}
#define TSBUFSIZE (100*188)
void tscheck(int ts)
{
uint8_t *buf;
uint8_t id;
int i, nts;
int len;
buf=(uint8_t *)malloc(TSBUFSIZE);
while(1) {
len=read(ts, buf, TSBUFSIZE);
if (len<0) {
continue;
}
if (buf[0]!=0x47) {
read(ts, buf, 1);
continue;
}
if (len%188) { /* should not happen */
printf("blah\n");
continue;
}
nts=len/188;
for (i=0; i<nts; i++)
proc_ts(i, buf+i*188);
}
}
static uint32_t root2gold(uint32_t root) static uint32_t root2gold(uint32_t root)
{ {
@ -29,16 +270,21 @@ int main(int argc, char **argv)
struct dddvb *dd; struct dddvb *dd;
struct dddvb_fe *fe; struct dddvb_fe *fe;
struct dddvb_params p; struct dddvb_params p;
uint32_t bandwidth = 8000000, frequency = 0, symbol_rate = 0, pol = DDDVB_UNDEF; uint32_t bandwidth = DDDVB_UNDEF, frequency = 0, symbol_rate = 0, pol = DDDVB_UNDEF;
uint32_t id = DDDVB_UNDEF, ssi = DDDVB_UNDEF, num = DDDVB_UNDEF, source = 0; uint32_t id = DDDVB_UNDEF, ssi = DDDVB_UNDEF, num = DDDVB_UNDEF, source = 0;
uint32_t mtype= DDDVB_UNDEF; uint32_t mtype= DDDVB_UNDEF;
uint32_t verbosity = 0; uint32_t verbosity = 0;
uint32_t get_ts = 1;
enum fe_code_rate fec = FEC_AUTO; enum fe_code_rate fec = FEC_AUTO;
enum fe_delivery_system delsys = ~0; enum fe_delivery_system delsys = ~0;
char *config = "config/"; char *config = "config/";
int fd = 0; int fd = 0;
int odvr = 0; int odvr = 0;
FILE *fout = stdout; FILE *fout = stdout;
int line = -1;
int color = 0;
pamdata iq;
while (1) { while (1) {
int cur_optind = optind ? optind : 1; int cur_optind = optind ? optind : 1;
@ -59,21 +305,44 @@ int main(int argc, char **argv)
{"mtype", required_argument, 0, 'm'}, {"mtype", required_argument, 0, 'm'},
{"verbosity", required_argument, 0, 'v'}, {"verbosity", required_argument, 0, 'v'},
{"open_dvr", no_argument, 0, 'o'}, {"open_dvr", no_argument, 0, 'o'},
{"tscheck", no_argument, 0, 't'},
{"tscheck_l", required_argument, 0, 'a'},
{"nodvr", no_argument , 0, 'q'},
{"pam", no_argument , 0, 'a'},
{"help", no_argument , 0, 'h'}, {"help", no_argument , 0, 'h'},
{0, 0, 0, 0} {0, 0, 0, 0}
}; };
c = getopt_long(argc, argv, c = getopt_long(argc, argv,
"c:i:f:s:d:p:hg:r:n:b:l:v:m:o", "e:c:i:f:s:d:p:hg:r:n:b:l:v:m:ota:q",
long_options, &option_index); long_options, &option_index);
if (c==-1) if (c==-1)
break; break;
switch (c) { switch (c) {
case 'e':
odvr = 2;
color = strtoul(optarg, NULL, 0);
break;
case 'o': case 'o':
fout = stderr; fout = stderr;
if (odvr) {
fprintf(fout,"Can't pipe dvr device when checking continuity\n");
break;
}
fprintf(fout,"Reading from dvr\n"); fprintf(fout,"Reading from dvr\n");
odvr = 1; odvr = 1;
break; break;
case 'a':
line = strtoul(optarg, NULL, 0);
case 't':
fout = stderr;
if (odvr) {
fprintf(fout,"Can't check continuity when piping dvr device\n");
break;
}
fprintf(fout,"performing continuity check\n");
odvr = 2;
break;
case 'c': case 'c':
config = strdup(optarg); config = strdup(optarg);
break; break;
@ -147,19 +416,24 @@ int main(int argc, char **argv)
delsys = SYS_ISDBT; delsys = SYS_ISDBT;
break; break;
case 'p': case 'p':
if (!strcmp(optarg, "h")) if (!strcmp(optarg, "h") || !strcmp(optarg, "H"))
pol = 1; pol = 1;
if (!strcmp(optarg, "v")) if (!strcmp(optarg, "v") || !strcmp(optarg, "V"))
pol = 0; pol = 0;
break; break;
case 'q':
get_ts = 0;
break;
case 'h': case 'h':
fprintf(fout,"ddzap [-d delivery_system] [-p polarity] [-c config_dir] [-f frequency(Hz)]\n" fprintf(fout,"ddzap [-d delivery_system] [-p polarity] [-c config_dir] [-f frequency(Hz)]\n"
" [-b bandwidth(Hz)] [-s symbol_rate(Hz)]\n" " [-b bandwidth(Hz)] [-s symbol_rate(Hz)]\n"
" [-g gold_code] [-r root_code] [-i id] [-n device_num]\n" " [-g gold_code] [-r root_code] [-i id] [-n device_num]\n"
" [-o (write dvr to stdout)]\n" " [-o (write dvr to stdout)]\n"
" [-l (tuner source for unicable)]\n"
" [-t [display line](continuity check)]\n"
"\n" "\n"
" delivery_system = C,S,S2,T,T2,J83B,ISDBC,ISDBT\n" " delivery_system = C,S,S2,T,T2,J83B,ISDBC,ISDBT\n"
" polarity = h,v\n" " polarity = h/H,v/V\n"
"\n"); "\n");
exit(-1); exit(-1);
default: default:
@ -188,6 +462,7 @@ int main(int argc, char **argv)
exit(-1); exit(-1);
} }
fprintf(fout,"dvbnum = %u\n", dd->dvbfe_num); fprintf(fout,"dvbnum = %u\n", dd->dvbfe_num);
dddvb_get_ts(dd, get_ts);
if (num != DDDVB_UNDEF) if (num != DDDVB_UNDEF)
fe = dddvb_fe_alloc_num(dd, delsys, num); fe = dddvb_fe_alloc_num(dd, delsys, num);
@ -208,6 +483,7 @@ int main(int argc, char **argv)
dddvb_set_id(&p, id); dddvb_set_id(&p, id);
dddvb_set_ssi(&p, ssi); dddvb_set_ssi(&p, ssi);
dddvb_dvb_tune(fe, &p); dddvb_dvb_tune(fe, &p);
#if 0 #if 0
{ {
uint8_t ts[188]; uint8_t ts[188];
@ -226,7 +502,7 @@ int main(int argc, char **argv)
cnr = dddvb_get_cnr(fe); cnr = dddvb_get_cnr(fe);
printf("stat=%02x, str=%lld.%03llddB, snr=%lld.%03llddB \n", printf("stat=%02x, str=%lld.%03llddB, snr=%lld.%03llddB \n",
stat, str/1000, abs(str%1000), cnr/1000, abs(cnr%1000)); stat, (long long int)str/1000,(long long int) abs(str%1000),(long long int) cnr/1000, (long long int)abs(cnr%1000));
sleep(1); sleep(1);
} }
} else { } else {
@ -245,7 +521,7 @@ int main(int argc, char **argv)
cnr = dddvb_get_cnr(fe); cnr = dddvb_get_cnr(fe);
fprintf(stderr,"stat=%02x, str=%lld.%03llddB, snr=%lld.%03llddB \n", fprintf(stderr,"stat=%02x, str=%lld.%03llddB, snr=%lld.%03llddB \n",
stat, str/1000, abs(str%1000), cnr/1000, abs(cnr%1000)); stat,(long long int) str/1000,(long long int) abs(str%1000),(long long int) cnr/1000, (long long int)abs(cnr%1000));
sleep(1); sleep(1);
} }
fprintf(stderr,"got lock on %s\n", fe->name); fprintf(stderr,"got lock on %s\n", fe->name);
@ -253,11 +529,31 @@ int main(int argc, char **argv)
"/dev/dvb/adapter%d/dvr%d",fe->anum, fe->fnum); "/dev/dvb/adapter%d/dvr%d",fe->anum, fe->fnum);
fprintf(stderr,"opening %s\n", filename); fprintf(stderr,"opening %s\n", filename);
if ((fd = open(filename ,O_RDONLY)) < 0){ if ((fd = open(filename ,O_RDONLY)) < 0){
fprintf(stderr,"Error opening input file:%s\n",filename); fprintf(stderr,"Error opening input file:%s\n",filename);
} }
while(1){ if (odvr > 0){
read(fd,buf,BUFFSIZE); switch (odvr){
write(fileno(stdout),buf,BUFFSIZE); case 1:
while(1){
read(fd,buf,BUFFSIZE);
write(fileno(stdout),buf,BUFFSIZE);
}
break;
case 2:
fprintf(stderr,"writing pamdata\n");
init_pamdata(&iq,color);
while(1){
pam_read_data(fd, &iq);
pam_write(STDOUT_FILENO, &iq);
}
break;
}
} else {
if( line >= 0 && line < 64 ){
snprintf(line_start,sizeof(line_start)-1,"\0337\033[%d;0H",line);
strncpy(line_end,"\0338",sizeof(line_end)-1);
}
tscheck(fd);
} }
} }
} }

View File

@ -41,7 +41,7 @@ int parse_config(struct dddvb *dd, char *name, char *sec,
memcpy(fname + config_len, "dddvb.conf", 11); memcpy(fname + config_len, "dddvb.conf", 11);
if ((f = fopen (fname, "r")) == NULL) { if ((f = fopen (fname, "r")) == NULL) {
printf("config fiile %s not found\n", fname); printf("config file %s not found\n", fname);
return -1; return -1;
} }

View File

@ -89,6 +89,7 @@ LIBDDDVB_EXPORTED struct dddvb *dddvb_init(char *config, uint32_t flags)
dddvb_dvb_init(dd); dddvb_dvb_init(dd);
global_dd = dd; global_dd = dd;
dd->get_ts = 1;
fail: fail:
pthread_mutex_unlock(&dddvb_mutex); pthread_mutex_unlock(&dddvb_mutex);
return dd; return dd;

View File

@ -75,6 +75,7 @@ struct dddvb_fe {
uint32_t level; uint32_t level;
uint32_t lock; uint32_t lock;
uint32_t quality; uint32_t quality;
uint32_t pls_code;
int64_t strength; int64_t strength;
int64_t cnr; int64_t cnr;
int64_t ber; int64_t ber;
@ -150,6 +151,9 @@ struct dddvb {
struct dddvb_fe dvbfe[DDDVB_MAX_DVB_FE]; struct dddvb_fe dvbfe[DDDVB_MAX_DVB_FE];
struct dddvb_ca dvbca[DDDVB_MAX_DVB_CA]; struct dddvb_ca dvbca[DDDVB_MAX_DVB_CA];
unsigned int get_ts:1;
}; };
int dddvb_dvb_init(struct dddvb *dd); int dddvb_dvb_init(struct dddvb *dd);

View File

@ -128,6 +128,9 @@ static int set_fe_input(struct dddvb_fe *fe, uint32_t fr,
} }
if (input != DDDVB_UNDEF) if (input != DDDVB_UNDEF)
set_property(fd, DTV_INPUT, input); set_property(fd, DTV_INPUT, input);
fprintf(stderr, "bw =%u\n", fe->param.param[PARAM_BW_HZ]);
if (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF)
set_property(fd, DTV_BANDWIDTH_HZ, fe->param.param[PARAM_BW_HZ]);
if (fe->param.param[PARAM_ISI] != DDDVB_UNDEF) if (fe->param.param[PARAM_ISI] != DDDVB_UNDEF)
set_property(fd, DTV_STREAM_ID, fe->param.param[PARAM_ISI]); set_property(fd, DTV_STREAM_ID, fe->param.param[PARAM_ISI]);
if (fe->param.param[PARAM_SSI] != DDDVB_UNDEF) if (fe->param.param[PARAM_SSI] != DDDVB_UNDEF)
@ -228,6 +231,7 @@ static int set_en50607(struct dddvb_fe *fe, uint32_t freq, uint32_t sr,
uint32_t input = 3 & (sat >> 6); uint32_t input = 3 & (sat >> 6);
int fd = fe->fd; int fd = fe->fd;
//printf("input = %u, sat = %u\n", input, sat&0x3f);
hor &= 1; hor &= 1;
cmd.msg[1] = slot << 3; cmd.msg[1] = slot << 3;
cmd.msg[1] |= ((t >> 8) & 0x07); cmd.msg[1] |= ((t >> 8) & 0x07);
@ -314,9 +318,13 @@ static int tune_sat(struct dddvb_fe *fe)
fe->scif_slot, fe->scif_freq, ds); fe->scif_slot, fe->scif_freq, ds);
pthread_mutex_unlock(&fe->dd->uni_lock); pthread_mutex_unlock(&fe->dd->uni_lock);
} else { } else {
uint32_t input = lnb;
if (input != DDDVB_UNDEF)
input = 3 & (input >> 6);
//set_property(fe->fd, DTV_INPUT, 3 & (lnb >> 6)); //set_property(fe->fd, DTV_INPUT, 3 & (lnb >> 6));
diseqc(fe->fd, lnb, fe->param.param[PARAM_POL], hi); diseqc(fe->fd, lnb, fe->param.param[PARAM_POL], hi);
set_fe_input(fe, freq, fe->param.param[PARAM_SR], ds, ~(0U)); set_fe_input(fe, freq, fe->param.param[PARAM_SR], ds, input);
} }
} }
@ -324,7 +332,7 @@ static int tune_c(struct dddvb_fe *fe)
{ {
struct dtv_property p[] = { struct dtv_property p[] = {
{ .cmd = DTV_CLEAR }, { .cmd = DTV_CLEAR },
{ .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] }, { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000},
{ .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ? { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ?
fe->param.param[PARAM_BW_HZ] : 8000000 }, fe->param.param[PARAM_BW_HZ] : 8000000 },
{ .cmd = DTV_SYMBOL_RATE, .u.data = fe->param.param[PARAM_SR] }, { .cmd = DTV_SYMBOL_RATE, .u.data = fe->param.param[PARAM_SR] },
@ -351,19 +359,28 @@ static int tune_c(struct dddvb_fe *fe)
return 0; return 0;
} }
static int tune_cable(struct dddvb_fe *fe) static int tune_j83b(struct dddvb_fe *fe)
{ {
uint32_t freq; struct dtv_property p[] = {
struct dvb_frontend_parameters p = { { .cmd = DTV_CLEAR },
.frequency = fe->param.param[PARAM_FREQ] * 1000, { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000},
.u.qam.symbol_rate = fe->param.param[PARAM_SR], { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ?
.u.qam.fec_inner = (fe->param.param[PARAM_FEC] != DDDVB_UNDEF) ? fe->param.param[PARAM_BW_HZ] : 6000000 },
(fe->param.param[PARAM_FEC]) : FEC_AUTO, { .cmd = DTV_SYMBOL_RATE, .u.data = (fe->param.param[PARAM_SR] != DDDVB_UNDEF) ?
.u.qam.modulation = fe->param.param[PARAM_MTYPE], fe->param.param[PARAM_SR] : 5056941},
}; { .cmd = DTV_TUNE },
set_property(fe->fd, DTV_DELIVERY_SYSTEM, SYS_DVBC_ANNEX_A); };
if (ioctl(fe->fd, FE_SET_FRONTEND, &p) == -1) { struct dtv_properties c;
perror("FE_SET_FRONTEND error"); int ret;
printf("tune_j83b()\n");
set_property(fe->fd, DTV_DELIVERY_SYSTEM, SYS_DVBC_ANNEX_B);
c.num = ARRAY_SIZE(p);
c.props = p;
ret = ioctl(fe->fd, FE_SET_PROPERTY, &c);
if (ret < 0) {
fprintf(stderr, "FE_SET_PROPERTY returned %d\n", ret);
return -1; return -1;
} }
return 0; return 0;
@ -374,7 +391,8 @@ static int tune_terr(struct dddvb_fe *fe)
struct dtv_property p[] = { struct dtv_property p[] = {
{ .cmd = DTV_CLEAR }, { .cmd = DTV_CLEAR },
{ .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 }, { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 },
{ .cmd = DTV_BANDWIDTH_HZ, .u.data = fe->param.param[PARAM_BW_HZ] }, { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ?
fe->param.param[PARAM_BW_HZ] : 8000000 },
{ .cmd = DTV_TUNE }, { .cmd = DTV_TUNE },
}; };
struct dtv_properties c; struct dtv_properties c;
@ -422,7 +440,8 @@ static int tune_c2(struct dddvb_fe *fe)
struct dtv_property p[] = { struct dtv_property p[] = {
{ .cmd = DTV_CLEAR }, { .cmd = DTV_CLEAR },
{ .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 }, { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 },
{ .cmd = DTV_BANDWIDTH_HZ, .u.data = fe->param.param[PARAM_BW_HZ] }, { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ?
fe->param.param[PARAM_BW_HZ] : 8000000 },
{ .cmd = DTV_STREAM_ID, .u.data = fe->param.param[PARAM_PLP] }, { .cmd = DTV_STREAM_ID, .u.data = fe->param.param[PARAM_PLP] },
{ .cmd = DTV_TUNE }, { .cmd = DTV_TUNE },
}; };
@ -446,7 +465,8 @@ static int tune_terr2(struct dddvb_fe *fe)
struct dtv_property p[] = { struct dtv_property p[] = {
{ .cmd = DTV_CLEAR }, { .cmd = DTV_CLEAR },
{ .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 }, { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 },
{ .cmd = DTV_BANDWIDTH_HZ, .u.data = fe->param.param[PARAM_BW_HZ] }, { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ?
fe->param.param[PARAM_BW_HZ] : 8000000 },
{ .cmd = DTV_STREAM_ID, .u.data = fe->param.param[PARAM_PLP] }, { .cmd = DTV_STREAM_ID, .u.data = fe->param.param[PARAM_PLP] },
{ .cmd = DTV_TUNE }, { .cmd = DTV_TUNE },
}; };
@ -470,7 +490,8 @@ static int tune_isdbt(struct dddvb_fe *fe)
struct dtv_property p[] = { struct dtv_property p[] = {
{ .cmd = DTV_CLEAR }, { .cmd = DTV_CLEAR },
{ .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 }, { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 },
{ .cmd = DTV_BANDWIDTH_HZ, .u.data = fe->param.param[PARAM_BW_HZ] }, { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ?
fe->param.param[PARAM_BW_HZ] : 6000000 },
{ .cmd = DTV_TUNE }, { .cmd = DTV_TUNE },
}; };
struct dtv_properties c; struct dtv_properties c;
@ -501,6 +522,9 @@ static int tune(struct dddvb_fe *fe)
case SYS_DVBC_ANNEX_A: case SYS_DVBC_ANNEX_A:
ret = tune_c(fe); ret = tune_c(fe);
break; break;
case SYS_DVBC_ANNEX_B:
ret = tune_j83b(fe);
break;
case SYS_DVBT: case SYS_DVBT:
ret = tune_terr(fe); ret = tune_terr(fe);
break; break;
@ -519,7 +543,7 @@ static int tune(struct dddvb_fe *fe)
return ret; return ret;
} }
static int open_dmx(struct dddvb_fe *fe) int open_dmx(struct dddvb_fe *fe)
{ {
char fname[80]; char fname[80];
struct dmx_pes_filter_params pesFilterParams; struct dmx_pes_filter_params pesFilterParams;
@ -611,10 +635,9 @@ void dddvb_fe_handle(struct dddvb_fe *fe)
uint32_t newtune, count = 0, max, nolock = 0; uint32_t newtune, count = 0, max, nolock = 0;
int ret; int ret;
printf("fe_handle\n");
open_dmx(fe); if (fe->dd->get_ts)
printf("fe_handle 2\n"); open_dmx(fe);
while (fe->state == 1) { while (fe->state == 1) {
pthread_mutex_lock(&fe->mutex); pthread_mutex_lock(&fe->mutex);
newtune = fe->n_tune; newtune = fe->n_tune;

View File

@ -331,6 +331,9 @@ static void calc_lq(struct dddvb_fe *fe)
int64_t str, snr; int64_t str, snr;
uint32_t mod, fec, ber_num, ber_den, trans, pilot = 0, quality = 0; uint32_t mod, fec, ber_num, ber_den, trans, pilot = 0, quality = 0;
get_property(fe->fd, DTV_TRANSMISSION_MODE, &fe->pls_code);
dbgprintf(DEBUG_DVB, "fe%d: pls=0x%02x\n", fe->nr, fe->pls_code);
get_stat(fe->fd, DTV_STAT_SIGNAL_STRENGTH, &st); get_stat(fe->fd, DTV_STAT_SIGNAL_STRENGTH, &st);
str = st.stat[0].svalue; str = st.stat[0].svalue;
dbgprintf(DEBUG_DVB, "fe%d: str=%lld\n", fe->nr, str); dbgprintf(DEBUG_DVB, "fe%d: str=%lld\n", fe->nr, str);

View File

@ -64,6 +64,9 @@ LIBDDDVB_EXPORTED int dddvb_ca_write(struct dddvb *dd, uint32_t nr, uint8_t *buf
LIBDDDVB_EXPORTED int dddvb_ca_read(struct dddvb *dd, uint32_t nr, uint8_t *buf, uint32_t len); LIBDDDVB_EXPORTED int dddvb_ca_read(struct dddvb *dd, uint32_t nr, uint8_t *buf, uint32_t len);
LIBDDDVB_EXPORTED int dddvb_ca_set_pmts(struct dddvb *dd, uint32_t nr, uint8_t **pmts); LIBDDDVB_EXPORTED int dddvb_ca_set_pmts(struct dddvb *dd, uint32_t nr, uint8_t **pmts);
static inline void dddvb_get_ts(struct dddvb *dd, uint32_t val) {
dd->get_ts = val;
};
static inline void dddvb_set_frequency(struct dddvb_params *p, uint32_t freq) { static inline void dddvb_set_frequency(struct dddvb_params *p, uint32_t freq) {
p->param[PARAM_FREQ] = freq; p->param[PARAM_FREQ] = freq;