diff --git a/Kbuild b/Kbuild index 2ce2955..b4e7482 100644 --- a/Kbuild +++ b/Kbuild @@ -2,6 +2,12 @@ # Makefile for the kernel multimedia device drivers. # +ifeq ($(KERNEL_DVB_CORE),y) +obj-y := ddbridge/ \ + frontends/ + +else obj-y := dvb-core/ \ ddbridge/ \ frontends/ +endif \ No newline at end of file diff --git a/Makefile b/Makefile index 28c954a..3040e6c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ kernelver ?= $(shell uname -r) +MDIR ?= KDIR ?= /lib/modules/$(kernelver)/build PWD := $(shell pwd) @@ -6,8 +7,11 @@ MODDEFS := CONFIG_DVB_CORE=m CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_DRXK=m CONFIG_DVB_ KBUILD_EXTMOD = $(PWD) -DDDVB_INC = "-I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux -I$(KBUILD_EXTMOD)/frontends" - +ifeq ($(KERNEL_DVB_CORE),y) +DDDVB_INC = "--include=$(KBUILD_EXTMOD)/include/dd_compat.h -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD) -DKERNEL_DVB_CORE=y" +else +DDDVB_INC = "--include=$(KBUILD_EXTMOD)/include/dd_compat.h -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux" +endif all: $(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) $(MODDEFS) modules NOSTDINC_FLAGS=$(DDDVB_INC) @@ -26,10 +30,11 @@ dep: DIR=`pwd`; (cd $(TOPDIR); make KBUILD_EXTMOD=$$DIR dep) install: all - $(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) modules_install - depmod -a + $(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) INSTALL_MOD_PATH=$(MDIR) modules_install + depmod $(kernelver) clean: rm -rf */.*.o.d */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules* + $(MAKE) -C apps clean diff --git a/README.md b/README.md index 8616941..ee2fcf2 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,9 @@ We can only accept patches which don't break compilation for older kernels (as f Due to this and other changes not approved by us the kernel version of the ddbridge driver might contain incompatiblities to this driver package. +For installation instructions see: + +http://support.digital-devices.eu/index.php?article=152 ### Prepare for Building TBD diff --git a/apps/Makefile b/apps/Makefile index 31a1ed5..882a8ea 100644 --- a/apps/Makefile +++ b/apps/Makefile @@ -1,4 +1,20 @@ -all: cit citin flashprog modt ddtest setmod ddflash setmod2 pls setmod3 +TARGETS = cit citin flashprog modt ddtest setmod ddflash setmod2 pls setmod3 modconfig ddinfo getiq modtest + +all: $(TARGETS) + +CFLAGS = -g -Wall -Wno-unused -Wno-format +FFMPEG := $(shell command -v ffmpeg 2> /dev/null) + +modtest: modtest.c + $(CC) -o modtest modtest.c -I../include/ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE64_SOURCE + +test.ts: +ifndef FFMPEG + $(error "ffmpeg is not available please install to create test.ts") +endif + ffmpeg -f lavfi -i testsrc=duration=10:size=1280x720:rate=30 \ + -f lavfi -i sine=f=440:b=4 -shortest -metadata \ + service_provider="DD" -metadata service_name="Test" test.ts cit: cit.c $(CC) -o cit cit.c -lpthread @@ -15,6 +31,22 @@ setmod2: setmod2.c setmod3: setmod3.c $(CC) -o setmod3 setmod3.c -I../include/ -%.o: %.c - $(CC) $(CFLAGS) -o $@ $< +modconfig: modconfig.c + $(CC) -o modconfig modconfig.c -I../include/ +clean: + rm cit citin flashprog modt ddtest setmod ddflash setmod2 pls setmod3 modconfig ddinfo getiq + +%: %.c + $(CC) $(CFLAGS) -I../ddbridge -I../include/ $< -o $@ + +%.o: %.c + $(CC) $(CFLAGS) -I../ddbridge -o $@ $< + + +clean: + for f in $(TARGETS) *.o *~ ; do \ + if [ -e "$$f" ]; then \ + rm "$$f" || exit 1; \ + fi \ + done diff --git a/apps/citin.c b/apps/citin.c index da1775d..5162911 100644 --- a/apps/citin.c +++ b/apps/citin.c @@ -10,7 +10,6 @@ #include #include #include -#include void proc_ts(int i, uint8_t *buf) { diff --git a/apps/ddinfo.c b/apps/ddinfo.c new file mode 100644 index 0000000..d32d86a --- /dev/null +++ b/apps/ddinfo.c @@ -0,0 +1,544 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint32_t u32; +typedef uint64_t u64; + +#include "../ddbridge/ddbridge-mci.h" +#include "../ddbridge/ddbridge-ioctl.h" + +char *Rolloff[8] = { + "0.35", + "0.25", + "0.20", + "0.10", + "0.05", + "0.15", + "rsvd", + "rsvd", +}; + +void dump(const uint8_t *b, int l) +{ + int i, j; + + for (j = 0; j < l; j += 16, b += 16) { + printf("%04x: ", j); + for (i = 0; i < 16; i++) + if (i + j < l) + printf("%02x ", b[i]); + else + printf(" "); + printf("\n"); + } +} + +void print_temp(struct mci_result *res) +{ + printf("Die temperature = %u\n", res->sx8_bist.temperature); +} + +int temp_info(int dev, uint32_t link) +{ + struct ddb_mci_msg msg = { + .link = link, + .cmd.command = SX8_CMD_GETBIST, + }; + int ret; + int i; + + ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg); + if (ret < 0) { + printf("Error: %d %d\n", ret, errno); + return ret; + } + if (msg.res.status & 0x80) { + printf("MCI errror %02x\n", msg.res.status); + return ret; + } + + print_temp(&msg.res); + printf("BIST info dump: "); + dump((uint8_t *) &msg.res, 16); + + return ret; +} + + +#define SIZE_OF_ARRAY(a) (sizeof(a)/sizeof(a[0])) + +char *DemodStatus[] = { + "Idle", + "IQ Mode", + "Wait for Signal", + "DVB-S2 Wait for MATYPE", + "DVB-S2 Wait for FEC", + "DVB-S1 Wait for FEC", + "Wait for TS", + "Unknown 7", + "Unknown 8", + "Unknown 9", + "Unknown 10", + "Unknown 11", + "Unknown 12", + "Unknown 13", + "Timeout", + "Locked", + "C2 Scan", +}; + +char* S2ModCods[32] = { +/* 0x00 */ "DummyPL" , + +// Legacy S2: index is S2_Modcod * 2 + short + +/* 0x01 */ "QPSK 1/4" , +/* 0x02 */ "QPSK 1/3" , +/* 0x03 */ "QPSK 2/5" , +/* 0x04 */ "QPSK 1/2" , +/* 0x05 */ "QPSK 3/5" , +/* 0x06 */ "QPSK 2/3" , +/* 0x07 */ "QPSK 3/4" , +/* 0x08 */ "QPSK 4/5" , +/* 0x09 */ "QPSK 5/6" , +/* 0x0A */ "QPSK 8/9" , +/* 0x0B */ "QPSK 9/10" , + +/* 0x0C */ "8PSK 3/5" , +/* 0x0D */ "8PSK 2/3" , +/* 0x0E */ "8PSK 3/4" , +/* 0x0F */ "8PSK 5/6" , +/* 0x10 */ "8PSK 8/9" , +/* 0x11 */ "8PSK 9/10" , + +/* 0x12 */ "16APSK 2/3" , +/* 0x13 */ "16APSK 3/4" , +/* 0x14 */ "16APSK 4/5" , +/* 0x15 */ "16APSK 5/6" , +/* 0x16 */ "16APSK 8/9" , +/* 0x17 */ "16APSK 9/10" , + +/* 0x18 */ "32APSK 3/4" , +/* 0x19 */ "32APSK 4/5" , +/* 0x1A */ "32APSK 5/6" , +/* 0x1B */ "32APSK 8/9" , +/* 0x1C */ "32APSK 9/10" , + +/* 0x1D */ "rsvd 0x1D" , +/* 0x1E */ "rsvd 0x1E" , +/* 0x1F */ "rsvd 0x1F" , +}; + + +///* 129 */ "VLSNR1" , +///* 131 */ "VLSNR2" , + +char* S2XModCods[59] = { +/* 0x42 */ "QPSK 13/45" , +/* 0x43 */ "QPSK 9/20" , +/* 0x44 */ "QPSK 11/20" , + +/* 0x45 */ "8APSK 5/9-L" , +/* 0x46 */ "8APSK 26/45-L" , +/* 0x47 */ "8PSK 23/36" , +/* 0x48 */ "8PSK 25/36" , +/* 0x49 */ "8PSK 13/18" , + +/* 0x4A */ "16APSK 1/2-L" , +/* 0x4B */ "16APSK 8/15-L" , +/* 0x4C */ "16APSK 5/9-L" , +/* 0x4D */ "16APSK 26/45" , +/* 0x4E */ "16APSK 3/5" , +/* 0x4F */ "16APSK 3/5-L" , +/* 0x50 */ "16APSK 28/45" , +/* 0x51 */ "16APSK 23/36" , +/* 0x52 */ "16APSK 2/3-L" , +/* 0x53 */ "16APSK 25/36" , +/* 0x54 */ "16APSK 13/18" , + +/* 0x55 */ "16APSK 7/9" , +/* 0x56 */ "16APSK 77/90" , + +/* 0x57 */ "32APSK 2/3-L" , +/* 0x58 */ "rsvd 32APSK" , +/* 0x59 */ "32APSK 32/45" , +/* 0x5A */ "32APSK 11/15" , +/* 0x5B */ "32APSK 7/9" , + +/* 0x5C */ "64APSK 32/45-L" , +/* 0x5D */ "64APSK 11/15" , +/* 0x5E */ "rsvd 64APSK" , +/* 0x5F */ "64APSK 7/9" , + +/* 0x60 */ "rsvd 64APSK" , +/* 0x61 */ "64APSK 4/5" , +/* 0x62 */ "rsvd 64APSK" , +/* 0x63 */ "64APSK 5/6" , + +/* 0x64 */ "128APSK 3/4" , +/* 0x65 */ "128APSK 7/9" , + +/* 0x66 */ "256APSK 29/45-L" , +/* 0x67 */ "256APSK 2/3-L" , +/* 0x68 */ "256APSK 31/45-L" , +/* 0x69 */ "256APSK 32/45" , +/* 0x6A */ "256APSK 11/15-L" , +/* 0x6B */ "256APSK 3/4" , + +/* 0x6C */ "QPSK 11/45-S" , +/* 0x6D */ "QPSK 4/15-S" , +/* 0x6E */ "QPSK 14/45-S" , +/* 0x6F */ "QPSK 7/15-S" , +/* 0x70 */ "QPSK 8/15-S" , +/* 0x71 */ "QPSK 32/45-S" , + +/* 0x72 */ "8PSK 7/15-S" , +/* 0x73 */ "8PSK 8/15-S" , +/* 0x74 */ "8PSK 26/45-S" , +/* 0x75 */ "8PSK 32/45-S" , + +/* 0x76 */ "16APSK 7/15-S" , +/* 0x77 */ "16APSK 8/15-S" , +/* 0x78 */ "16APSK 26/45-S" , +/* 0x79 */ "16APSK 3/5-S" , +/* 0x7A */ "16APSK 32/45-S" , + +/* 0x7B */ "32APSK 2/3-S" , +/* 0x7C */ "32APSK 32/45-S" , +}; + +char* S2Xrsvd[] = { +/* 250 */ "rsvd 8PSK" , +/* 251 */ "rsvd 16APSK" , +/* 252 */ "rsvd 32APSK" , +/* 253 */ "rsvd 64APSK" , +/* 254 */ "rsvd 256APSK" , +/* 255 */ "rsvd 1024APSK" , +}; + +char* PunctureRates[32] = { +/* 0x00 */ "QPSK 1/2", // DVB-S1 +/* 0x01 */ "QPSK 2/3", // DVB-S1 +/* 0x02 */ "QPSK 3/4", // DVB-S1 +/* 0x03 */ "QPSK 5/6", // DVB-S1 +/* 0x04 */ "QPSK 6/7", // DSS +/* 0x05 */ "QPSK 7/8", // DVB-S1 +/* 0x06 */ "rsvd 6.0", +/* 0x07 */ "rsvd 7.0", +}; + +int mci_bb(int dev, uint32_t link, uint8_t demod) +{ + struct ddb_mci_msg msg = { + .link = link, + .cmd.command = MCI_CMD_GET_BBHEADER, + .cmd.demod = demod, + .cmd.get_bb_header.select = 0, + }; + struct mci_result *res = &msg.res; + int ret; + int i; + + ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg); + if (ret < 0) { + printf("Error: %d %d\n", ret, errno); + return ret; + } + if (res->bb_header.valid) { + printf("MATYPE1: %02x\n", res->bb_header.matype_1); + printf("MATYPE2: %02x\n", res->bb_header.matype_2); + } + return ret; +} + +void print_info(int dev, uint32_t link, uint8_t demod, struct mci_result *res) +{ + if (res->status == MCI_DEMOD_STOPPED) { + printf("\nDemod %u: stopped\n", demod); + return; + } + + printf("\nDemod %u:\n", demod); + if (res->status == MCI_DEMOD_LOCKED) { + switch (res->mode) { + case 0: + case M4_MODE_DVBSX: + if (res->dvbs2_signal_info.standard != 1) { + int short_frame = 0, pilots = 0; + char *modcod = "unknown"; + uint8_t pls = res->dvbs2_signal_info.pls_code; + + if ((pls >= 128) || ((res->dvbs2_signal_info.roll_off & 0x7f) > 2)) + printf("Demod Locked: DVB-S2X\n"); + else + printf("Demod Locked: DVB-S2\n"); + printf("PLS-Code: %u\n", res->dvbs2_signal_info.pls_code); + mci_bb(dev, link, demod); + if (pls >= 250) { + pilots = 1; + modcod = S2Xrsvd[pls - 250]; + } else if (pls >= 132) { + pilots = pls & 1; + short_frame = pls > 216; + modcod = S2XModCods[(pls - 132)/2]; + } else if (pls < 128) { + pilots = pls & 1; + short_frame = pls & 2; + modcod = S2ModCods[pls / 4]; + } + printf("Roll-Off: %s\n", Rolloff[res->dvbs2_signal_info.roll_off & 7]); + printf("Pilots: %s\n", pilots ? "On" : "Off"); + printf("Frame: %s\n", short_frame ? "Short" : "Normal"); + } else { + printf("Demod Locked: DVB-S\n"); + printf("PR: %s\n", + PunctureRates[res->dvbs2_signal_info.pls_code & 0x07]); + } + printf("Inversion: %s\n", (res->dvbs2_signal_info.roll_off & 0x80) ? "on": "off"); + break; + case M4_MODE_DVBT: + printf("Locked DVB-T\n"); + break; + case M4_MODE_DVBT2: + printf("Locked DVB-T2\n"); + break; + } + printf("SNR: %.2f dB\n", (float) res->dvbs2_signal_info.signal_to_noise / 100); + printf("Packet Errors: %u\n", res->dvbs2_signal_info.packet_errors); + printf("BER Numerator: %u\n", res->dvbs2_signal_info.ber_numerator); + printf("BER Denom.: %u\n", res->dvbs2_signal_info.ber_denominator); + } else { + printf("Demod State: %s\n", + res->status < SIZE_OF_ARRAY(DemodStatus) ? DemodStatus[res->status] : "?"); + + } + printf("Frequency: %u Hz\n", res->dvbs2_signal_info.frequency); + printf("Symbol Rate: %u Symbols/s\n", res->dvbs2_signal_info.symbol_rate); + printf("Channel Power: %.2f dBm\n", (float) res->dvbs2_signal_info.channel_power / 100); + if (res->dvbs2_signal_info.band_power > -10000) + printf("Band Power: %.2f dBm\n", (float) res->dvbs2_signal_info.band_power / 100); + +} + +int readreg(int dev, uint32_t reg, uint32_t link, uint32_t *val) +{ + struct ddb_reg ddbreg; + + ddbreg.reg = reg + (link << 28); + if (ioctl(dev, IOCTL_DDB_READ_REG, &ddbreg) < 0) + return -1; + *val = ddbreg.val; + return 0; +} + +void mci_firmware(int dev, uint32_t link) +{ + union { + uint32_t u[4]; + char s[16]; + } version; + + readreg(dev, MIC_INTERFACE_VER , link, &version.u[0]); + readreg(dev, MIC_INTERFACE_VER + 4, link, &version.u[1]); + readreg(dev, MIC_INTERFACE_VER + 8, link, &version.u[2]); + readreg(dev, MIC_INTERFACE_VER + 12, link, &version.u[3]); + + printf("MCI firmware: %s.%d\n", &version.s, version.s[15]); +} + + +int mci_info(int dev, uint32_t link, uint8_t demod) +{ + struct ddb_mci_msg msg = { + .link = link, + .cmd.command = MCI_CMD_GETSIGNALINFO, + .cmd.demod = demod + }; + int ret; + int i; + + ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg); + if (ret < 0) { + printf("Error: %d %d\n", ret, errno); + return ret; + } + + print_info(dev, link, demod, &msg.res); + return ret; +} + +static int get_id(int fd, int link, struct ddb_id *id) +{ + struct ddb_reg ddbreg; + + if (link == 0) { + if (ioctl(fd, IOCTL_DDB_ID, id) < 0) + return -1; + return 0; + } + ddbreg.reg = 8 + (link << 28); + if (ioctl(fd, IOCTL_DDB_READ_REG, &ddbreg) < 0) + return -1; + id->vendor = ddbreg.val; + id->device = ddbreg.val >> 16; + + ddbreg.reg = 12 + (link << 28); + if (ioctl(fd, IOCTL_DDB_READ_REG, &ddbreg) < 0) + return -1; + id->subvendor = ddbreg.val; + id->subdevice = ddbreg.val >> 16; + + ddbreg.reg = 0 + (link << 28); + if (ioctl(fd, IOCTL_DDB_READ_REG, &ddbreg) < 0) + return -1; + id->hw = ddbreg.val; + + ddbreg.reg = 4 + (link << 28); + if (ioctl(fd, IOCTL_DDB_READ_REG, &ddbreg) < 0) + return -1; + id->regmap = ddbreg.val; + return 0; +} + +static char *id2name(uint16_t id) +{ + switch (id) { + case 0x222: + return "MOD"; + case 0x0009: + return "MAX SX8"; + case 0x000b: + return "MAX SX8 Basic"; + case 0x000a: + return "MAX M4"; + default: + return " "; + } +} + +static int card_info(int ddbnum, int demod) +{ + char ddbname[80]; + struct ddb_id ddbid; + int ddb, ret, link, links = 1, i; + struct ddb_id id; + + sprintf(ddbname, "/dev/ddbridge/card%d", ddbnum); + ddb = open(ddbname, O_RDWR); + if (ddb < 0) + return -3; + + for (link = 0; link < links; link++) { + ret = get_id(ddb, link, &id); + if (ret < 0) + goto out; + if (!link) { + switch (id.device) { + case 0x20: + links = 4; + break; + case 0x300: + case 0x301: + case 0x307: + links = 2; + break; + + default: + break; + } + } + printf("\n\nCard %s link %u id %04x (%s):\n", + ddbname, link, id.device, id2name(id.device)); + printf("HW %08x REGMAP %08x FW %u.%u\n", + id.hw, id.regmap, (id.hw & 0xff0000) >> 16, (id.hw & 0xffff)); + switch (id.device) { + case 0x0009: + mci_firmware(ddb, link); + if (demod >= 0) + mci_info(ddb, link, demod); + else { + for (i = 0; i < 8; i++) + mci_info(ddb, link, i); + } + temp_info(ddb, link); + break; + case 0x000a: + mci_firmware(ddb, link); + if (demod >= 0) + mci_info(ddb, link, demod); + else { + for (i = 0; i < 4; i++) + mci_info(ddb, link, i); + } + break; + default: + break; + } + } + +out: + close(ddb); + return ret; +} + +int main(int argc, char*argv[]) +{ + int fd = -1, all = 1, i, ret = 0; + char fn[128]; + int32_t device = -1, demod = -1; + + while (1) { + int cur_optind = optind ? optind : 1; + int option_index = 0; + int c; + static struct option long_options[] = { + {"device", required_argument, 0, 'd'}, + {"demod", required_argument, 0, 'n'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "ad:n:", + long_options, &option_index); + if (c == -1) + break; + switch (c) { + case 'd': + device = strtoul(optarg, NULL, 0); + break; + case 'n': + demod = strtoul(optarg, NULL, 0); + break; + case 'a': + all = 1; + break; + default: + break; + } + } + if (optind < argc) { + printf("too many arguments\n"); + exit(1); + } + if (device >=0) + ret = card_info(device, demod); + else + for (i = 0; i < 100; i++) { + ret = card_info(i, -1); + + if (ret == -3) /* could not open, no more cards! */ + break; + if (ret < 0) + return i; /* fatal error */ + } +} diff --git a/apps/flashprog.c b/apps/flashprog.c index fdac041..0276890 100644 --- a/apps/flashprog.c +++ b/apps/flashprog.c @@ -275,6 +275,7 @@ int main(int argc, char **argv) case SPANSION_S25FL116K: case SPANSION_S25FL164K: case WINBOND_W25Q16JV: + case WINBOND_W25Q32JV: err = FlashWritePageMode(ddb,FlashOffset,buffer,BufferSize,0x1C); break; } diff --git a/apps/getiq.c b/apps/getiq.c new file mode 100644 index 0000000..59c8734 --- /dev/null +++ b/apps/getiq.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint32_t u32; +typedef uint64_t u64; + +#include "../ddbridge/ddbridge-mci.h" +#include "../ddbridge/ddbridge-ioctl.h" + +void print_iq(struct mci_result *res, int fd) +{ + dprintf(fd, "%d,%d\n", res->iq_symbol.i, res->iq_symbol.q); +} + +int get_iq(int dev, uint32_t link, uint8_t demod, int fd) +{ + struct ddb_mci_msg msg = { + .link = link, + .cmd.command = MCI_CMD_GET_IQSYMBOL, + .cmd.demod = demod, + .cmd.get_iq_symbol.tap = 0, + .cmd.get_iq_symbol.point = 0, + }; + int ret; + int i; + + ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg); + if (ret < 0) { + printf("Error: %d %d\n", ret, errno); + return ret; + } + if (msg.res.status & 0x80) { + printf("MCI errror %02x\n", msg.res.status); + return ret; + } + + print_iq(&msg.res, fd); + return ret; +} + + +#define SIZE_OF_ARRAY(a) (sizeof(a)/sizeof(a[0])) + +int main(int argc, char*argv[]) +{ + char ddbname[80]; + int fd = -1, all = 1, i, ret = 0, ddb; + char fn[128]; + int32_t device = -1, demod = -1; + + while (1) { + int cur_optind = optind ? optind : 1; + int option_index = 0; + int c; + static struct option long_options[] = { + {"device", required_argument, 0, 'd'}, + {"demod", required_argument, 0, 'n'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "ad:n:", + long_options, &option_index); + if (c == -1) + break; + switch (c) { + case 'd': + device = strtoul(optarg, NULL, 0); + break; + case 'n': + demod = strtoul(optarg, NULL, 0); + break; + case 'a': + all = 1; + break; + default: + break; + } + } + if (optind < argc) { + printf("too many arguments\n"); + exit(1); + } + sprintf(ddbname, "/dev/ddbridge/card%d", device); + ddb = open(ddbname, O_RDWR); + if (ddb < 0) + return -3; + for (i = 0; i < 20000; i++) + get_iq(ddb, 0, demod, 1); +} diff --git a/apps/modconfig.c b/apps/modconfig.c new file mode 100644 index 0000000..05e8530 --- /dev/null +++ b/apps/modconfig.c @@ -0,0 +1,531 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint32_t u32; +typedef uint64_t u64; + +#include "../ddbridge/ddbridge-mci.h" +#include "../ddbridge/ddbridge-ioctl.h" + +struct mconf { + int set_output; + int set_channels; + int fd; + + struct mci_command channels; + struct mci_command stream; + struct mci_command output; +}; + +void strim(char *s) +{ + int l = strlen(s); + + while (l && isspace(s[l-1])) + l--; + s[l] = 0; +} + +void parse(char *fname, char *sec, void *priv, void (*cb)(void *, char *, char *)) +{ + char line[256], csec[80], par[80], val[80], *p; + FILE *f; + + if ((f = fopen(fname, "r")) == NULL) + return; + while ((p = fgets(line, sizeof(line), f))) { + if (*p == '\r' || *p == '\n' || *p == '#') + continue; + if (*p == '[') { + if ((p = strtok(line + 1, "]")) == NULL) + continue; + strncpy(csec, p, sizeof(csec)); + if (!strcmp(sec, csec) && cb) + cb(priv, NULL, NULL); + continue; + } + if (!(p = strtok(line, "="))) + continue; + while (isspace(*p)) + p++; + strncpy(par, p, sizeof(par)); + strim(par); + if (!(p = strtok(NULL, "="))) + continue; + while (isspace(*p)) + p++; + strncpy (val, p, sizeof(val)); + strim(val); + if (!strcmp(sec, csec) && cb) + cb(priv, par, val); + } + if (!strcmp(sec, csec) && cb) + cb(priv, NULL, NULL); + fclose(f); +} + +struct param_table_entry { + int value; + char* name; +}; + +struct param_table_entry mod_standard_table[] = { + { .name = "0", .value = MOD_STANDARD_GENERIC }, + { .name = "GENERIC", .value = MOD_STANDARD_GENERIC }, + + { .name = "1", .value = MOD_STANDARD_DVBT_8 }, + { .name = "DVBT_8", .value = MOD_STANDARD_DVBT_8 }, + { .name = "DVBT2_8", .value = MOD_STANDARD_DVBT_8 }, + + { .name = "2", .value = MOD_STANDARD_DVBT_7 }, + { .name = "DVBT_7", .value = MOD_STANDARD_DVBT_7 }, + { .name = "DVBT2_7", .value = MOD_STANDARD_DVBT_7 }, + + { .name = "3", .value = MOD_STANDARD_DVBT_6 }, + { .name = "DVBT_6", .value = MOD_STANDARD_DVBT_6 }, + { .name = "DVBT2_6", .value = MOD_STANDARD_DVBT_6 }, + + { .name = "4", .value = MOD_STANDARD_DVBT_5 }, + { .name = "DVBT_5", .value = MOD_STANDARD_DVBT_5 }, + { .name = "DVBT2_5", .value = MOD_STANDARD_DVBT_5 }, + + { .name = "8", .value = MOD_STANDARD_DVBC_8 }, + { .name = "DVBC_8", .value = MOD_STANDARD_DVBC_8 }, + + { .name = "9", .value = MOD_STANDARD_DVBC_7 }, + { .name = "DVBC_7", .value = MOD_STANDARD_DVBC_7 }, + + { .name = "10", .value = MOD_STANDARD_DVBC_6 }, + { .name = "DVBC_6", .value = MOD_STANDARD_DVBC_6 }, + + { .name = "11", .value = MOD_STANDARD_J83B_QAM64 }, + { .name = "J83B_QAM64", .value = MOD_STANDARD_J83B_QAM64 }, + + { .name = "12", .value = MOD_STANDARD_J83B_QAM256 }, + { .name = "J83B_QAM256", .value = MOD_STANDARD_J83B_QAM256 }, + + { .name = "13", .value = MOD_STANDARD_ISDBC_QAM64 }, + { .name = "ISDBC_QAM64", .value = MOD_STANDARD_ISDBC_QAM64 }, + { .name = "J83C_QAM64", .value = MOD_STANDARD_ISDBC_QAM64 }, + + { .name = "14", .value = MOD_STANDARD_ISDBC_QAM256 }, + { .name = "ISDBC_QAM256", .value = MOD_STANDARD_ISDBC_QAM256 }, + { .name = "J83C_QAM256", .value = MOD_STANDARD_ISDBC_QAM256 }, + + { .name = NULL, .value = 0 } +}; + +struct param_table_entry stream_format_table[] = { + { .name = "0", .value = MOD_FORMAT_DEFAULT }, + { .name = "default", .value = MOD_FORMAT_DEFAULT }, + + { .name = "1", .value = MOD_FORMAT_IQ16 }, + { .name = "IQ16", .value = MOD_FORMAT_IQ16 }, + + { .name = "2", .value = MOD_FORMAT_IQ8 }, + { .name = "IQ8", .value = MOD_FORMAT_IQ8 }, + + { .name = "3", .value = MOD_FORMAT_IDX8 }, + { .name = "IDX8", .value = MOD_FORMAT_IDX8 }, + + { .name = "4", .value = MOD_FORMAT_TS }, + { .name = "TS", .value = MOD_FORMAT_TS }, + + { .name = NULL, .value = 0 } +}; + + +struct param_table_entry guard_interval_table[] = { + { .name = "0", .value = MOD_DVBT_GI_1_32 }, + { .name = "1/32", .value = MOD_DVBT_GI_1_32 }, + + { .name = "1", .value = MOD_DVBT_GI_1_16 }, + { .name = "1/16", .value = MOD_DVBT_GI_1_16 }, + + { .name = "2", .value = MOD_DVBT_GI_1_8 }, + { .name = "1/8", .value = MOD_DVBT_GI_1_8 }, + + { .name = "3", .value = MOD_DVBT_GI_1_4 }, + { .name = "1/4", .value = MOD_DVBT_GI_1_4 }, + { .name = NULL, .value = 0 } +}; + +struct param_table_entry puncture_rate_table[] = { + { .name = "1", .value = MOD_DVBT_PR_1_2 }, + { .name = "1/2", .value = MOD_DVBT_PR_1_2 }, + + { .name = "2", .value = MOD_DVBT_PR_2_3 }, + { .name = "2/3", .value = MOD_DVBT_PR_2_3 }, + + { .name = "3", .value = MOD_DVBT_PR_3_4 }, + { .name = "3/4", .value = MOD_DVBT_PR_3_4 }, + + { .name = "5", .value = MOD_DVBT_PR_5_6 }, + { .name = "5/6", .value = MOD_DVBT_PR_5_6 }, + + { .name = "7", .value = MOD_DVBT_PR_7_8 }, + { .name = "7/8", .value = MOD_DVBT_PR_7_8 }, + + { .name = NULL, .value = 0 } +}; + +struct param_table_entry dvbt_constellation_table[] = { + { .name = "0", .value = MOD_DVBT_QPSK }, + { .name = "qpsk", .value = MOD_DVBT_QPSK }, + + { .name = "1", .value = MOD_DVBT_16QAM }, + { .name = "16qam", .value = MOD_DVBT_16QAM }, + { .name = "qam16", .value = MOD_DVBT_16QAM }, + + { .name = "2", .value = MOD_DVBT_64QAM }, + { .name = "64qam", .value = MOD_DVBT_64QAM }, + { .name = "qam64", .value = MOD_DVBT_64QAM }, + + { .name = NULL, .value = 0 } +}; + +struct param_table_entry qam_modulation_table[] = { + { .name = "0", .value = MOD_QAM_DVBC_16 }, + { .name = "qam_dvbc_16", .value = MOD_QAM_DVBC_16 }, + + { .name = "1", .value = MOD_QAM_DVBC_32 }, + { .name = "qam_dvbc_32", .value = MOD_QAM_DVBC_32 }, + + { .name = "2", .value = MOD_QAM_DVBC_64 }, + { .name = "qam_dvbc_64", .value = MOD_QAM_DVBC_64 }, + + { .name = "3", .value = MOD_QAM_DVBC_128 }, + { .name = "qam_dvbc_128", .value = MOD_QAM_DVBC_128 }, + + { .name = "4", .value = MOD_QAM_DVBC_256 }, + { .name = "qam_dvbc_256", .value = MOD_QAM_DVBC_256 }, + + { .name = "5", .value = MOD_QAM_J83B_64 }, + { .name = "qam_j83b_64", .value = MOD_QAM_J83B_64 }, + + { .name = "6", .value = MOD_QAM_DVBC_256 }, + { .name = "qam_j83b_256", .value = MOD_QAM_J83B_256 }, + + { .name = "7", .value = MOD_QAM_GENERIC }, + { .name = "qam_generic", .value = MOD_QAM_GENERIC }, + + { .name = "8", .value = MOD_QAM_ISDBC_64 }, + { .name = "qam_isdbc_64", .value = MOD_QAM_ISDBC_64 }, + + { .name = "9", .value = MOD_QAM_ISDBC_256 }, + { .name = "qam_isdbc_256", .value = MOD_QAM_ISDBC_256 }, + + { .name = NULL, .value = 0 } +}; + +int parse_param(char *val, struct param_table_entry *table, int *value) { + if (value) { + *value = 0; + if (table) { + while (table->name) { + if( !strcasecmp(val,table->name)) { + *value = table->value; + printf("%s=%u\n", val, *value); + return 0; + } + table++; + } + } + } + printf("unknown value %s\n", val); + return -1; +} + +void dump(const uint8_t *b, int l) +{ + int i, j; + + for (j = 0; j < l; j += 16, b += 16) { + for (i = 0; i < 16; i++) + if (i + j < l) + printf("%02x ", b[i]); + else + printf(" "); + printf(" | "); + for (i = 0; i < 16; i++) + if (i + j < l) + putchar((b[i] > 31 && b[i] < 127) ? b[i] : '.'); + printf("\n"); + } +} + +int mci_cmd(int dev, struct mci_command *cmd) +{ + int ret; + struct ddb_mci_msg msg; + uint8_t status; + + memset(&msg, 0, sizeof(msg)); + msg.link = 0; + memcpy(&msg.cmd, cmd, sizeof(msg.cmd)); + //dump((const uint8_t *) &msg.cmd, sizeof(msg.cmd)); + ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg); + if (ret < 0) { + dprintf(2, "mci_cmd error %d (%s)\n", errno, strerror(errno)); + return ret; + } + status = msg.res.status; + if (status == MCI_STATUS_OK) + return ret; + if (status == MCI_STATUS_UNSUPPORTED) { + dprintf(2, "Unsupported MCI command\n"); + return ret; + } + if (status == MCI_STATUS_INVALID_PARAMETER) { + dprintf(2, "Invalid MCI parameters\n"); + return ret; + } + return ret; +} + +struct mci_command msg_channels = { + .mod_command = MOD_SETUP_CHANNELS, + .mod_channel = 0, + .mod_stream = 0, + .mod_setup_channels[0] = { + .flags = MOD_SETUP_FLAG_FIRST|MOD_SETUP_FLAG_LAST|MOD_SETUP_FLAG_VALID, + .standard = MOD_STANDARD_DVBT_8, + .num_channels = 25, + .frequency = 474000000, + }, +}; + +struct mci_command msg_stream = { + .mod_command = MOD_SETUP_STREAM, + .mod_channel = 1, + .mod_stream = 0, + .mod_setup_stream = { + .standard = MOD_STANDARD_DVBC_8, +#if 0 + .ofdm = { + .fft_size = 1, + .guard_interval = 0, + } +#endif + }, +}; + +struct mci_command msg_output = { + .mod_command = MOD_SETUP_OUTPUT, + .mod_channel = 0, + .mod_stream = 0, + .mod_setup_output = { + .connector = MOD_CONNECTOR_F, + .num_channels = 16, + .unit = MOD_UNIT_DBUV, + .channel_power = 5000, + }, +}; + +void output_cb(void *priv, char *par, char *val) +{ + struct mconf *mc = (struct mconf *) priv; + + if (!par && !val) { + mc->set_output = 1; + return; + } + if (!strcasecmp(par, "connector")) { + if (!strcasecmp(val, "F")) { + mc->output.mod_setup_output.connector = MOD_CONNECTOR_F; + } else if (!strcasecmp(val, "SMA")) { + mc->output.mod_setup_output.connector = MOD_CONNECTOR_SMA; + } else if (!strcasecmp(val, "OFF")) { + mc->output.mod_setup_output.connector = MOD_CONNECTOR_OFF; + } else + printf("invalid connector\n"); + } else if (!strcasecmp(par, "power")) { + mc->output.mod_setup_output.channel_power = (int16_t) (strtod(val, NULL) * 100.0); + } else if (!strcasecmp(par, "channels")) { + mc->output.mod_setup_output.num_channels = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "unit")) { + if (!strcasecmp(val, "DBUV")) { + mc->output.mod_setup_output.unit = MOD_UNIT_DBUV; + } else if (!strcasecmp(val, "DBM")) { + mc->output.mod_setup_output.unit = MOD_UNIT_DBM; + } else + printf("invalid unit\n"); + } else + printf("invalid output parameter: %s\n", par); +} + +void channels_cb(void *priv, char *par, char *val) +{ + struct mconf *mc = (struct mconf *) priv; + int value; + + if (!par && !val) { + mc->set_channels = 1; + return; + } + if (!strcasecmp(par, "frequency")) { + mc->channels.mod_setup_channels[0].frequency = (uint32_t) (strtod(val, NULL) * 1000000.0); + printf("frequency = %u\n", mc->channels.mod_setup_channels[0].frequency); + } else if (!strcasecmp(par, "channels")) { + mc->channels.mod_setup_channels[0].num_channels = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "standard")) { + if (!parse_param(val,mod_standard_table, &value)) + mc->channels.mod_setup_channels[0].standard = value; + printf("standard = %u\n", value); + } else if (!strcasecmp(par, "offset")) { + mc->channels.mod_setup_channels[0].offset = (uint32_t) (strtod(val, NULL) * 1000000.0); + } else if (!strcasecmp(par, "bandwidth")) { + mc->channels.mod_setup_channels[0].bandwidth = (uint32_t) (strtod(val, NULL) * 1000000.0); + mc->channels.mod_setup_channels[0].offset = + mc->channels.mod_setup_channels[0].bandwidth / 2; + } else + printf("invalid channels parameter: %s\n", par); +} + +void streams_cb(void *priv, char *par, char *val) +{ + struct mconf *mc = (struct mconf *) priv; + int value; + + if (!par && !val) { + return; + } + if (!strcasecmp(par, "fft_size")) { + mc->stream.mod_setup_stream.ofdm.fft_size = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "guard_interval")) { + if (!parse_param(val, guard_interval_table, &value)) + mc->stream.mod_setup_stream.ofdm.guard_interval = value; + } else if (!strcasecmp(par, "puncture_rate")) { + if (!parse_param(val, puncture_rate_table, &value)) + mc->stream.mod_setup_stream.ofdm.puncture_rate = value; + } else if (!strcasecmp(par, "constellation")) { + if (!parse_param(val,dvbt_constellation_table,&value)) + mc->stream.mod_setup_stream.ofdm.constellation = value; + } else if (!strcasecmp(par, "cell_identifier")) { + mc->stream.mod_setup_stream.ofdm.cell_identifier = strtol(val, NULL, 0); + } else if (!strcasecmp(par, "modulation")) { + if (!parse_param(val, qam_modulation_table, &value)) + mc->stream.mod_setup_stream.qam.modulation = value; + } else if (!strcasecmp(par, "rolloff")) { + mc->stream.mod_setup_stream.qam.rolloff = strtol(val, NULL, 0); + } else if (!strcasecmp(par, "standard")) { + if (!parse_param(val,mod_standard_table,&value)) + mc->stream.mod_setup_stream.standard = value; + } else if (!strcasecmp(par, "stream_format")) { + if (!parse_param(val,stream_format_table,&value)) + mc->stream.mod_setup_stream.stream_format = value; + } else if (!strcasecmp(par, "symbol_rate")) { + mc->stream.mod_setup_stream.symbol_rate = (uint32_t) (strtod(val, NULL) * 1000000.0); + } else if (!strcasecmp(par, "channel")) { + mc->stream.mod_channel = strtol(val, NULL, 10); + } else if (!strcasecmp(par, "stream")) { + mc->stream.mod_stream = strtol(val, NULL, 10); + printf("set stream %u to channel %u\n", mc->stream.mod_stream, mc->stream.mod_channel); + mci_cmd(mc->fd, &mc->stream); + } else + printf("invalid streams parameter: %s = %s\n", par, val); +} + +int mci_lic(int dev) +{ + struct ddb_mci_msg msg = { + .cmd.command = CMD_EXPORT_LICENSE, + .cmd.get_bb_header.select = 0, + }; + struct mci_result *res = &msg.res; + int ret; + int i; + + ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg); + if (ret < 0) { + printf("Error: %d %d\n", ret, errno); + return ret; + } + if (res->bb_header.valid) { + printf("MATYPE1: %02x\n", res->bb_header.matype_1); + printf("MATYPE2: %02x\n", res->bb_header.matype_2); + } + dump((const uint8_t *)&res->license, sizeof(res->license)); + return ret; +} + +int main(int argc, char*argv[]) +{ + int fd = -1; + char fn[128]; + uint32_t device = 0; + uint32_t frequency = 0; + char *configname = "modulator.conf"; + struct mconf mc; + + memset(&mc, 0, sizeof(mc)); + mc.channels = msg_channels; + mc.stream = msg_stream; + mc.output = msg_output; + + while (1) { + int cur_optind = optind ? optind : 1; + int option_index = 0; + int c; + static struct option long_options[] = { + {"device", required_argument, 0, 'd'}, + {"config", required_argument, 0, 'c'}, + {"help", no_argument, 0, 'h'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, "d:c:", + long_options, &option_index); + if (c == -1) + break; + switch (c) { + case 'd': + device = strtoul(optarg, NULL, 0); + break; + case 'c': + configname = optarg; + break; + case 'h': + dprintf(2, "modconfig [-d device_number] [-c config_file]\n"); + break; + default: + break; + } + } + if (optind < argc) { + printf("too many arguments\n"); + exit(1); + } + //snprintf(fn, 127, "/dev/ddbridge/card%u", device); + snprintf(fn, 127, "/dev/dvb/adapter%u/mod0", device); + fd = open(fn, O_RDWR); + if (fd < 0) { + dprintf(2, "Could not open %s\n", fn); + return -1; + } + //mci_lic(fd); + mc.fd = fd; + parse(configname, "channels", (void *) &mc, channels_cb); + if (mc.set_channels) { + printf("setting channels.\n"); + mci_cmd(fd, &mc.channels); + } + parse(configname, "streams", (void *) &mc, streams_cb); + parse(configname, "output", (void *) &mc, output_cb); + if (mc.set_output) { + printf("setting output.\n"); + mci_cmd(fd, &mc.output); + } +} diff --git a/apps/modtest.c b/apps/modtest.c new file mode 100644 index 0000000..4b1e806 --- /dev/null +++ b/apps/modtest.c @@ -0,0 +1,1321 @@ + +// for systems without O_LARGEFILE +#ifndef O_LARGEFILE +#define O_LARGEFILE 0 +#endif +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef uint8_t u8; +typedef uint16_t u16; +typedef int16_t s16; +typedef uint32_t u32; +typedef uint64_t u64; + +#include "../ddbridge/ddbridge-mci.h" +#include "../ddbridge/ddbridge-ioctl.h" + +#define NIT_PID 0x0010 +#define MAXNIT 1024 +#define DEFAULT_BIT_RATE_C (50870588ULL) +#define DEFAULT_BIT_RATE_T (31668449ULL) +#define TS_SIZE (188) +#define START_FREQ_T (474000000) +#define START_FREQ_C (114000000) +static int adapt = 1; +static uint32_t start_freq = START_FREQ_C; +static int dvbt = 0; +static int writeNIT = 0; + +int timest = 1; + +typedef struct section_data_t { + uint8_t *section; + uint16_t sec_length; + uint16_t sec_pos; + uint8_t pack_num; +} section_data; + + +typedef struct transponder_{ + uint16_t tpid; + uint8_t delsys; + uint32_t freq; + uint8_t qam; + uint32_t symbolrate; + uint8_t bandwidth; + uint8_t guard; + uint8_t code_rate; + uint8_t trans_mode; +} transponder; + +typedef struct write_data_t { + int fd_in; + int *fd_out; + char *name; + int chans; + transponder tp[32]; +} write_data; + +#define ADAPT_FIELD 0x20 +#define MAX_PCR (2576980377599ULL) // max pcr 2^33*300-1 +#define PCR_FAC (2048ULL) +#define MAXPCR (MAX_PCR*PCR_FAC) +#define PCR_FLAG 0x10 +#define OPCR_FLAG 0x08 + +//++++++++++++++++++++++++++++++++CRC+++++++++++++++++++++++++++++++++++++ +static uint32_t dvb_crc_table[256] = { + 0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9, + 0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005, + 0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61, + 0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd, + 0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9, + 0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75, + 0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011, + 0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd, + 0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039, + 0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5, + 0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81, + 0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d, + 0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49, + 0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95, + 0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1, + 0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d, + 0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae, + 0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072, + 0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16, + 0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca, + 0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde, + 0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02, + 0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066, + 0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba, + 0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e, + 0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692, + 0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6, + 0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a, + 0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e, + 0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2, + 0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686, + 0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a, + 0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637, + 0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb, + 0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f, + 0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53, + 0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47, + 0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b, + 0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff, + 0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623, + 0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7, + 0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b, + 0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f, + 0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3, + 0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7, + 0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b, + 0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f, + 0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3, + 0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640, + 0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c, + 0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8, + 0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24, + 0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30, + 0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec, + 0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088, + 0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654, + 0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0, + 0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c, + 0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18, + 0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4, + 0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0, + 0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c, + 0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668, + 0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4 +}; + + +uint32_t dvb_crc32(uint8_t *data, int len) +{ + int i; + uint32_t crc=0xffffffff; + + for (i=0; i>24)^(data[i]))&0xff]; + return crc; +} + +void dvb_set_crc32(uint8_t *data, int len) +{ + uint32_t crc; + + crc=dvb_crc32(data, len); + data[len] = (uint8_t)(crc>>24); + data[len+1] = (uint8_t)(crc>>16); + data[len+2] = (uint8_t)(crc>>8); + data[len+3] = (uint8_t)(crc); +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//+++++++++++++++++++++++++++++++++++PCR++++++++++++++++++++++++++++++++++ + +uint16_t get_pid(uint8_t *pid) +{ + uint16_t pp; + + pp = (pid[0] & 0x1f) << 8; + pp |= pid[1] &0xff; + return pp; +} + +void set_pid(uint16_t pid, uint8_t *p) +{ + p[0] = (p[0] & 0xE0) | ((uint8_t) (pid >> 8 ) & 0x1F); + p[1] = (uint8_t) (pid); +} + +int pcr_in_msecs(uint64_t pcr) +{ + uint64_t PCR; + + PCR = pcr/PCR_FAC; + + return PCR/27000; +} + + +int check_pcr(uint8_t *buf) +{ + + if (buf[0] != 0x47) { + fprintf(stderr,"Not a TS packet header in check_pcr\n"); + return -1; + } + + if (buf[1] & 0x80) { + fprintf(stderr,"Corrupt packet in check_pcr\n"); + return -1; + } + + if (!(buf[3] & ADAPT_FIELD)){ +// fprintf(stderr,"no adaptation field\n"); + return 0; //no adapt. field + } + if (!buf[4]){ +// fprintf(stderr,"no adaptation field length\n"); + return 0; //No adaptation field length + } + if (! (buf[5] & PCR_FLAG) ){ +// fprintf(stderr,"no PCR flag\n"); + return 0; // no PCR FLAG + } +// fprintf(stderr,"Found pcr\n"); + return 1; +} + +uint8_t *get_pcr(uint8_t *buf) +{ + return buf+6; +} + +uint64_t convert_pcr(uint8_t *b){ + uint64_t pcr; + + pcr = ((uint64_t) b[0] << 25) | ((uint64_t) b[1] << 17) | + ((uint64_t) b[2] << 9) | ((uint64_t) b[3] << 1) | + ((uint64_t) b[4] >> 7); + pcr *= 300; + pcr += ((b[4] & 1) << 8) | b[5]; + return pcr*PCR_FAC; +} + +int find_pcr(uint8_t *buf, int l, int last) +{ + int c = 0; + while (buf[c] != 0x47) c++; + + if (last){ + c+=((l-c)/TS_SIZE-1)*TS_SIZE; + while (buf[c] != 0x47) c--; + while (c >=0 && !check_pcr(buf+c)) c-=TS_SIZE; + if (check_pcr(buf+c)) return c; + else return -1; + } else { + while (c < l && !check_pcr(buf+c)) c+=TS_SIZE; + if (check_pcr(buf+c)) return c; + else return -1; + } +} +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//+++++++++++++++++++++++++++++++++++TS PACKETS+++++++++++++++++++++++++++ + +void write_filler(uint8_t *buf) +{ + int j; + uint8_t *p; + + p = buf; + *p++ = 0x47; + *p++ = 0x1F; + *p++ = 0xFF; + *p++ = 0x00; + for(j = 0; j < TS_SIZE-4; j+=1 ) *p++ = 0x00; +} + +void setbcd(uint8_t *p, int freq, int b, int e) +{ + int i; + int f = freq/e; + int r = b%2; + + if (r){ + p[b/2] = ( (f % 10) >> 4) & 0xF0; + f = f / 10; + } + for ( i= b/2; i > 0; i--){ + p[i-1] = (f % 10) & 0x0F; + f = f / 10; + p[i-1] |= ( (f % 10) << 4) & 0xF0; + f = f / 10; + } +} + +static int write_cable_delsys_descriptor (uint8_t *buf, int blength, + transponder *tp) +{ + int length = 0; + uint8_t *p; + + p = buf; + length = 11; + + if (length > (int)(0xFF) || length+2 >blength){ + fprintf(stderr,"Not enough space for cable delsys descriptor %d, %d\n", + length, blength); + return -1; + } + p[0]= 0x44; // cable delivery system descriptor + p[1]= 0x0B; // length always 11 + setbcd(p+2, tp->freq, 8, 100); + p[6] = 0xFF; // reserved + p[7]= 0x02; // FEC_outer + p[8]= tp->qam; // QAM + setbcd(p+9,tp->symbolrate, 7, 100); + p[12]|= 0x0F; + + return length+2; +} + +static int write_terrestrial_delsys_descriptor (uint8_t *buf, int blength, + transponder *tp) +{ + int length = 0; + uint8_t *p; + uint32_t freq = tp->freq/10; + p = buf; + length = 11; + + if (length > (int)(0xFF) || length+2 >blength){ + fprintf(stderr,"Not enough space for cable delsys descriptor %d, %d\n", + length, blength); + return -1; + } + p[0]= 0x5a; // terretrial delivery system descriptor + p[1]= 0x0B; // length always 11 + p[2]= (freq >> 24) & 0xFF; + p[3]= (freq >> 16) & 0xFF; + p[4]= (freq >> 8) & 0xFF; + p[5]= freq & 0xFF; + p[6]= ((tp->bandwidth&0x7)<<5) |0x1f; + //bandwidth 8MHz 000,no priority 1, + //no time slice 1, no mpe-fce 1 + p[7]= 0x00 |((tp->qam & 0x03) << 6) | (tp->code_rate &0x07); + //64-QAM 10, no hierarchy 000, 7/8 100 + p[8]= 0x00 | ((tp->guard &0x03) <<3 )|((tp->trans_mode &0x03) << 1); + // no LP 000, 1/32 guard 00, 8k mode 01, no other freq 0 + + p[9]=0xff; + p[10]=0xff; + p[11]=0xff; + p[12]=0xff; + + return length+2; +} + +int CreateNIT(uint8_t *NIT, transponder *tp, int start, int stop, + char *nname, uint16_t nid, uint8_t secnum, uint8_t lastsec) +{ + uint8_t *p,*lp; + int c = 0; + int cc; + int i; + uint16_t TableLen = 0; + int slen; + + p = NIT; + + p[0] = 0x40; // Table Id NIT = 0x40 + + p[1] = 0x00; // Table length determined at end + p[2] = 0x00; + + p[3] = (nid >> 8) & 0xFF; // network id + p[4] = nid & 0xFF; + + p[5] = 0xC3; // seq number + p[6] = secnum; // section number + p[7] = lastsec; // last section number + + +// Network descriptor + p[8] = 0xF0; // network descriptor length + p[9] = 0x00; // set later + TableLen = 7; + c = 10; + p[c] = 0x40; // Network name descriptor + + slen = 0; + + slen = strlen(nname); + p[c+1] = slen; + memcpy(p+c+2,nname,slen); + + p[8] = 0xF0 | (((2+slen) >> 8) &0x0F); + p[9] = ((2+slen) & 0xFF); + TableLen += 2+slen; + c += 2+slen; + + +// Transport stream loop + p[c] = 0xF0; // transport stream loop length + p[c+1] = 0x00; // set later + cc = c+1; + + TableLen += 2; + c += 2; + slen = 0; + for (i= start; i < stop; i++){ + p[c] = (uint8_t)( tp[i].tpid >> 8 ); //transport stream id + p[c+1]= (uint8_t)( tp[i].tpid ); + p[c+2]= (nid >> 8) &0xFF; // orig network id + p[c+3]= nid & 0xFF; // id + + lp = p+c+4; + p[c+4]= 0xF0; // descriptor loop length + p[c+5]= 0x0D; // 13 for cable delivery descriptor + c += 6; + switch (tp->delsys){ + case SYS_DVBC_ANNEX_A: + slen = write_cable_delsys_descriptor (p+c, MAXNIT-c, &tp[i]); + break; + case SYS_DVBT: + slen = write_terrestrial_delsys_descriptor (p+c, MAXNIT-c, &tp[i]); + break; + default: + slen = 0; + } + c+=slen; + + lp[0] = 0xF0 | (((slen) >> 8) &0x0F); + lp[1] = ((slen) & 0xFF); + + + TableLen += 6+slen; + } + + p[cc-1]= 0xF0 | (((c-cc-1) >> 8) &0x0F); + p[cc] = ((c-cc-1) & 0xFF); + + TableLen += 4; + + p[1] = 0xF0 | ((TableLen >> 8) & 0x0F); + p[2] = (uint8_t)(TableLen) & 0xFF; + + + dvb_set_crc32(NIT, TableLen + 3 -4 ); + return TableLen+3; + +} + +void init_sec_data(section_data *s, uint8_t *sec, uint16_t seclength) +{ + uint16_t seclen = 0; + + s->section = sec; + seclen |= ((sec[1] & 0x0F) << 8); + seclen |= (sec[2] & 0xFF); + seclen += 3; + if (seclen > 3){ + s->sec_length = seclen; + if(seclength && seclen != seclength) + fprintf(stderr,"Setting seclength (%d) %d\n",seclength, seclen); + } else s->sec_length = seclength; + + s->sec_pos = 0; + s->pack_num = 0; +} + +void write_sec_pack(section_data *s, uint8_t *ts_pack, uint16_t pid) +{ + uint8_t *p = ts_pack; + uint16_t rest = 0; + uint16_t len = s->sec_length - s->sec_pos; + uint16_t pload = 0; + + *p++ = 0x47; + set_pid(pid,p); + if (!s->sec_pos){ + *p |= 0x40; + } else { + *p &= ~0x40; + } + p += 2; + *p++ = 0x10 | (s->pack_num & 0x0f); + s->pack_num += 1; + if (!s->sec_pos) *p++=0x00; + pload = TS_SIZE - (p - ts_pack); + if (pload > len) pload = len; + memcpy( p, s->section + s->sec_pos, pload); + p += pload; + rest = TS_SIZE - (p - ts_pack); + if (rest > 0) + memset(p, 0xff, rest); + s->sec_pos += pload; + if (s->sec_pos == s->sec_length){ + s->sec_pos = 0; + } +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//++++++++++++++++++++++++++++++++MAIN ROUTINE++++++++++++++++++++++++++++ + +#define OBSIZE (672*TS_SIZE) +#define BSIZE (7*OBSIZE) + +void write_mods(write_data *wd) +{ + uint8_t NIT[MAXNIT]; + section_data sec; + off64_t inflength,c=0; + uint8_t buffer[BSIZE]; + uint8_t obuffer[OBSIZE]; + int ci=0,w=0; + int isdvr=0; + int first = 0; + int last = 0; + uint64_t fpcr = 0; + uint64_t lpcr = 0; + uint64_t delta_pcr = 0; + uint64_t in_prate, out_prate; + int slen = 0; + + if (dvbt){ + out_prate = DEFAULT_BIT_RATE_T / (8*TS_SIZE); + } else { + out_prate = DEFAULT_BIT_RATE_C / (8*TS_SIZE); + } + slen = CreateNIT(NIT, wd->tp, 0, wd->chans, "DD", 1, 0, 0); + + init_sec_data(&sec, NIT, slen); + in_prate = 0; + + inflength = lseek64(wd->fd_in, 0, SEEK_END); + inflength = TS_SIZE*(inflength/TS_SIZE); + if (inflength <= 0){ + if (inflength == 0 || errno == ESPIPE){ + isdvr = 1; + fprintf(stderr,"Non seekable file, handling as dvr\n"); + } else { + fprintf(stderr,"Error in lseek, aborting\n"); + return; + } + } + + if (!isdvr){ + fprintf(stderr,"Input file length: %.2f MiB\n",inflength/1024./1024.); + lseek64(wd->fd_in,0,SEEK_SET); + } + + fprintf(stderr,"Starting %s\n",wd->name); + while (1) { + int wc=0; + first = 0; + last = 0; + + if ((ci=read(wd->fd_in,buffer,BSIZE))<0) return; + + first = find_pcr(buffer, ci, 0); + last = find_pcr(buffer, ci, 1); + if (first == last){ + fprintf(stderr,"Input buffer too small\n" + "first %d last %d length %d pidf 0x%x\n", first/TS_SIZE, + last/TS_SIZE, + ci/TS_SIZE, get_pid(buffer+first+1)); + } + fpcr = convert_pcr(get_pcr(buffer+first)); + lpcr = convert_pcr(get_pcr(buffer+last)); + if (lpcr > fpcr) delta_pcr = lpcr - fpcr; + else delta_pcr = (MAXPCR-fpcr)+lpcr; + int packs = (last-first)/TS_SIZE; + in_prate = ((packs*10000/pcr_in_msecs(delta_pcr))+5)/10; + +#if 0 + fprintf(stderr,"delta_pcr %d ms npack %d packet_rate in: %d out: %d\n", + pcr_in_msecs(delta_pcr), + packs, in_prate, out_prate); + fprintf(stderr,"Input bitrate %.2f MBit output bitrate %.2f MBit\n", + (in_prate*TS_SIZE*8)/1000000.0, + (out_prate*TS_SIZE*8)/1000000.0); +#endif + + if (in_prate > out_prate){ + fprintf(stderr,"Input bitrate (%.2f MBit) larger than " + "possible output bitrate (%.2f MBit)\n", + (in_prate*TS_SIZE*8)/1000000.0, + (out_prate*TS_SIZE*8)/1000000.0); + exit(1); + } + + int filler = (out_prate*10/in_prate+5)/10-1; + int d=0; + int rest=0; + for (int s = 0; s < ci; s+=TS_SIZE){ + memcpy(obuffer+d, buffer+s, TS_SIZE*sizeof(uint8_t)); + d+=TS_SIZE; + int fill = (OBSIZE - d)/TS_SIZE; + if (fill < filler) rest = filler - fill; + else fill = filler; +// fprintf(stderr,"d %d fill %d filler %d %d %d\n", d, fill,filler,s,ci); + int nit = 0; + for(int i=0;i < fill; i++){ + if (writeNIT && nit < 4 ) { + write_sec_pack(&sec, obuffer+d, NIT_PID); + nit++; + } else write_filler(obuffer+d); + d+=TS_SIZE; + } + if (d >= OBSIZE){ + for (int m = 0; m < wd->chans; m++){ + int lc = 0; + while (lc < OBSIZE){ + if ((w=write(wd->fd_out[m],obuffer+lc,OBSIZE-lc))<0){ + fprintf(stderr,"Problem writing to modulator from %s (%d %d) %s\n", + wd->name, w, ci,strerror(errno)); + return; + } + wc += w; + lc+=w; + d = 0; + } + } + } + + for(int i=0;i < rest; i++){ + write_filler(obuffer+d); + d+=TS_SIZE; + } + rest = 0; + } + if (inflength){ + c+=ci; + fprintf(stderr,"written %d %d%%\n",(int)c,(int)((100*c)/inflength)); + if (c >=inflength ){ + fprintf(stderr,"Restarting stream %s\n",wd->name); + lseek64(wd->fd_in,0,SEEK_SET); + c = 0; + } + } + } +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//+++++++++++++++++++++++++++++++++DVB DEVICES++++++++++++++++++++++++++++ + +#define DVB_TUNE 0 +#define DVB_MOD 1 +#define DVB_CA 2 +#define MAX_ADAPT 32 + +typedef struct dvb_devices_t { + int adapters; + int dtype[MAX_ADAPT]; + int ndevs[MAX_ADAPT]; + uint64_t snr[MAX_ADAPT]; + uint64_t hwid[MAX_ADAPT]; + uint64_t devid0[MAX_ADAPT]; +} dvb_devices; + + +static int check_tuner(int adapt) +{ + char device[35]; + int front = 0; + int done = 0; + + while (!done) { + snprintf(device,34,"/dev/dvb/adapter%d/frontend%d",adapt,front); +// fprintf(stderr,"Checking for %s\n", device); + if(access(device, F_OK) < 0) + done=1; + else { + front++; + } + } + return front; +} + +static int check_ca(int adapt) +{ + char device[25]; + int ca = 0; + int done = 0; + + while (!done) { + snprintf(device,24,"/dev/dvb/adapter%d/ci%d",adapt,ca); + if(access(device, F_OK) < 0) + done=1; + else { + ca++; + } + } + return ca; +} + +static int check_modulator(int adapt) +{ + char device[25]; + int mod = 0; + int done = 0; + + while (!done) { + snprintf(device,24,"/dev/dvb/adapter%d/mod%d",adapt,mod); + if(access(device, F_OK) < 0) + done=1; + else { + mod++; + } + } + return mod; +} + + +static int check_dvb(dvb_devices *ddevices){ + int done = 0; + int nadapt = 0; + int maxmod = 0; + int maxfront = 0; + int maxca = 0; + int i; + int adapter =0; + + while ( nadapt < MAX_ADAPT && !done){ + maxca = check_ca(nadapt); + maxmod = check_modulator(nadapt); + maxfront = check_tuner(nadapt); + + if (maxmod){ + ddevices->dtype[nadapt] = DVB_MOD; + ddevices->ndevs[nadapt] = maxmod; + maxmod = 0; + nadapt++; + } else { + if (maxfront) { + ddevices->dtype[nadapt] = DVB_TUNE; + ddevices->ndevs[nadapt] = maxfront; + maxfront = 0; + nadapt++; + } else { + if (maxca) { + ddevices->dtype[nadapt] = DVB_CA; + ddevices->ndevs[nadapt] = maxca; + maxca = 0; + nadapt++; + } else { + done = 1; + } + } + } + } + ddevices->adapters = nadapt; + if (!nadapt) return -1; + + fprintf(stderr,"Found %d dvb adapters\n",nadapt); + for (i=0; idtype[i]){ + case DVB_TUNE: + fprintf(stderr," Adapter %d is a TUNER CARD with %d FRONTENDS\n", i, ddevices->ndevs[i]); + break; + case DVB_MOD: + fprintf(stderr," Adapter %d is a MODULATOR CARD with %d MODULATORS\n", i, ddevices->ndevs[i]); + adapter = i; + break; + case DVB_CA: + fprintf(stderr," Adapter %d is a CI CARD with %d CA \n",i,ddevices->ndevs[i]); + break; + } + } + return adapter; +} + + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//++++++++++++++++++++++++++++++++DVBT MOD++++++++++++++++++++++++++++++++ + +static int mci_cmd(int dev, struct mci_command *cmd) +{ + int ret; + struct ddb_mci_msg msg; + uint8_t status; + + memset(&msg, 0, sizeof(msg)); + msg.link = 0; + memcpy(&msg.cmd, cmd, sizeof(msg.cmd)); + //dump((uint8_t *) &msg.cmd, sizeof(msg.cmd)); + ret = ioctl(dev, IOCTL_DDB_MCI_CMD, &msg); + if (ret < 0) { + dprintf(2, "mci_cmd error %s\n",strerror(errno)); + return ret; + } + status = msg.res.status; + if (status == MCI_STATUS_OK) + return ret; + if (status == MCI_STATUS_UNSUPPORTED) { + dprintf(2, "Unsupported MCI command\n"); + return ret; + } + if (status == MCI_STATUS_INVALID_PARAMETER) { + dprintf(2, "Invalid MCI parameters\n"); + return ret; + } + return ret; +} + +int mci_set_output(int fd, uint8_t connector, uint8_t nchannels, uint8_t unit, + int16_t power) +{ + char con[14]; + char un[6]; + struct mci_command msg_output = { + .mod_command = MOD_SETUP_OUTPUT, + .mod_channel = 0, + .mod_stream = 0, + .mod_setup_output = { + .connector = MOD_CONNECTOR_F, + .num_channels = 14, + .unit = MOD_UNIT_DBUV, + .channel_power = 9000, + }, + }; + + msg_output.mod_setup_output.connector = connector; + msg_output.mod_setup_output.num_channels = nchannels; + msg_output.mod_setup_output.unit = unit; + msg_output.mod_setup_output.channel_power = power; + + + switch (connector){ + case MOD_CONNECTOR_F: + snprintf(con, 14, "F-Connector"); + break; + + case MOD_CONNECTOR_SMA: + snprintf(con, 14, "SMA-Connector"); + break; + + case MOD_CONNECTOR_OFF: + snprintf(con, 14, "off"); + break; + + default: + fprintf(stderr,"unknown connector in modulator setup\n"); + return -1; + break; + } + switch (unit){ + case MOD_UNIT_DBUV: + snprintf(un, 6, " dBuV"); + break; + + case MOD_UNIT_DBM: + snprintf(un, 6, " dBm"); + break; + + default: + fprintf(stderr,"unknow power unit in modulator setup\n"); + return -1; + break; + } + + fprintf(stderr,"Setting DVBT Modulator output to %s, %d channels, power %f%s\n", + con, nchannels, (double)power/100, un ); + + return mci_cmd(fd,&msg_output); +} + +int mci_set_output_simple(int adapt, uint8_t nchannels) +{ + char fn[128]; + int re = 0; + + snprintf(fn, 127, "/dev/dvb/adapter%u/mod0", adapt); + int fd = open(fn, O_RDWR); + if (fd < 0) { + fprintf(stderr, "Could not open %s\n", fn); + return -1; + } + + re = mci_set_output(fd, MOD_CONNECTOR_F, nchannels, MOD_UNIT_DBUV, 9000); + close(fd); + return re; +} + +int mci_set_channels(int fd, uint32_t freq, uint8_t nchan, uint8_t standard, + uint32_t offset, uint32_t bandw) +{ + char stand[25]; + struct mci_command msg_channels = { + .mod_command = MOD_SETUP_CHANNELS, + .mod_channel = 0, + .mod_stream = 0, + .mod_setup_channels[0] = { + .flags = MOD_SETUP_FLAG_FIRST|MOD_SETUP_FLAG_LAST|MOD_SETUP_FLAG_VALID, + .standard = MOD_STANDARD_DVBT_8, + .num_channels = 25, + .frequency = 474000000, + }, + }; + + msg_channels.mod_setup_channels[0].frequency = freq; + msg_channels.mod_setup_channels[0].num_channels = nchan; + msg_channels.mod_setup_channels[0].standard = standard; + if (standard == MOD_STANDARD_GENERIC){ + msg_channels.mod_setup_channels[0].offset = offset; + msg_channels.mod_setup_channels[0].bandwidth = bandw; + } + + switch(standard){ + case MOD_STANDARD_GENERIC: + snprintf(stand, 24, "MOD_STANDARD_GENERIC"); + break; + + case MOD_STANDARD_DVBT_8: + snprintf(stand, 24, "MOD_STANDARD_DVBT_8"); + break; + + case MOD_STANDARD_DVBT_7: + snprintf(stand, 24, "MOD_STANDARD_DVBT_7"); + break; + + case MOD_STANDARD_DVBT_6: + snprintf(stand, 24, "MOD_STANDARD_DVBT_6"); + break; + + case MOD_STANDARD_DVBT_5: + snprintf(stand, 24, "MOD_STANDARD_DVBT_5"); + break; + + default: + fprintf(stderr,"unknown standard in channels setup\n"); + return -1; + break; + + } + fprintf(stderr,"Setting DVBT Modulator channels to %d HZ, %d channels, %s\n", + freq, nchan, stand); + + return mci_cmd(fd,&msg_channels); +} + +int mci_set_channels_simple(int adapt, uint32_t freq, uint8_t nchan) +{ + + char fn[128]; + int re = 0; + + snprintf(fn, 127, "/dev/dvb/adapter%u/mod0", adapt); + int fd = open(fn, O_RDWR); + if (fd < 0) { + fprintf(stderr, "Could not open %s\n", fn); + return -1; + } + + re = mci_set_channels(fd, freq, nchan, MOD_STANDARD_DVBT_8, 0, 0); + close(fd); + return re; +} + +int mci_set_stream( int fd, uint8_t stream, uint8_t channel, uint8_t standard, + uint8_t stream_format, uint32_t symbol_rate, + uint8_t modulation, uint8_t rolloff, + uint8_t fft_size, uint8_t guard_interval, + uint8_t puncture_rate, uint8_t constellation, + uint16_t cell_identifier) +{ + struct mci_command msg_stream = { + .mod_command = MOD_SETUP_STREAM, + .mod_channel = 0, + .mod_stream = 0, + .mod_setup_stream = { + .standard = MOD_STANDARD_DVBC_8, + }, + }; + + msg_stream.mod_channel = channel; + msg_stream.mod_stream = stream; + msg_stream.mod_setup_stream.standard = standard; + msg_stream.mod_setup_stream.stream_format = stream_format; + if (symbol_rate) + msg_stream.mod_setup_stream.symbol_rate = symbol_rate; + if (modulation) + msg_stream.mod_setup_stream.qam.modulation = modulation; + if (rolloff) + msg_stream.mod_setup_stream.qam.rolloff = rolloff; + msg_stream.mod_setup_stream.ofdm.fft_size = fft_size; + msg_stream.mod_setup_stream.ofdm.guard_interval = guard_interval; + msg_stream.mod_setup_stream.ofdm.puncture_rate = puncture_rate; + msg_stream.mod_setup_stream.ofdm.constellation = constellation; + if (cell_identifier) + msg_stream.mod_setup_stream.ofdm.cell_identifier = cell_identifier; + + fprintf(stderr,"Setting DVBT Stream %d to channel %d\n",stream, channel); + + return mci_cmd(fd,&msg_stream); + +} + +void set_dvbt_mods(int adapt, int chans, uint32_t start_freq, write_data *wd) +{ + if ((mci_set_output_simple(adapt, chans) < 0)|| + (mci_set_channels_simple(adapt, start_freq, chans)< 0)) + { + fprintf(stderr,"Error setting up DVBT Modulator\n"); + exit(1); + } + wd->chans = chans; + wd->fd_out = (int *)malloc(chans*sizeof(int)); + memset(wd->fd_out,0,chans*sizeof(int)); + + for (int i = 0; i < chans; i++){ + char *device; + int fd; + + wd->tp[i].tpid = 1; // all the same transport stream id + wd->tp[i].delsys = SYS_DVBT; + wd->tp[i].freq = start_freq+8000000*i; + wd->tp[i].qam = 2; + wd->tp[i].symbolrate = 0; + wd->tp[i].bandwidth = 0; + wd->tp[i].guard = 0; + wd->tp[i].code_rate = 4; + wd->tp[i].trans_mode = MOD_STANDARD_DVBT_8; + + device = malloc(sizeof(char)*40); + snprintf(device,35,"/dev/dvb/adapter%d/mod%d",adapt,i); + fd = open(device, O_RDWR); + if( fd < 0 ) + { + fprintf(stderr,"Error opening %s : %s\n",device,strerror(errno)); + free(device); + exit(1); + } + + mci_set_stream( fd, i, i, MOD_STANDARD_DVBT_8, 4, 0, 0, 0, 1, 0, 4, 2, 0); + close(fd); + free(device); + } +} + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//++++++++++++++++++++++++++++++++DVBC MOD++++++++++++++++++++++++++++++++ + +static int set_property(int fd, uint32_t cmd, uint32_t data) +{ + struct dtv_property p; + struct dtv_properties c; + int ret; + + p.cmd = cmd; + c.num = 1; + c.props = &p; + p.u.data = data; + ret = ioctl(fd, FE_SET_PROPERTY, &c); + if (ret < 0) { + fprintf(stderr, "FE_SET_PROPERTY returned %d\n", errno); + return -1; + } + return 0; +} + +static int set_input_bitrate(int fd, uint64_t data) +{ + struct dtv_property p; + struct dtv_properties c; + int ret; + + p.cmd = MODULATOR_INPUT_BITRATE; + c.num = 1; + c.props = &p; + p.u.data64 = data; + ret = ioctl(fd, FE_SET_PROPERTY, &c); + if (ret < 0) { + fprintf(stderr, "FE_SET_PROPERTY returned %d\n", errno); + return -1; + } + return 0; +} + +void set_dvbc_mods(int adapt, int chans, uint32_t start_freq, write_data *wd) +{ + uint32_t freq = start_freq; + uint8_t qam = QAM_256; + uint32_t sym = 6900000; + + wd->chans = chans; + wd->fd_out = (int *)malloc(chans*sizeof(int)); + memset(wd->fd_out,0,chans*sizeof(int)); + + for (int i = 0; i < chans; i++){ + char *device; + int fd; + + wd->tp[i].tpid = i; + wd->tp[i].delsys = SYS_DVBC_ANNEX_A; + wd->tp[i].freq = freq; + wd->tp[i].qam = qam; + wd->tp[i].symbolrate = sym; + wd->tp[i].bandwidth = 0; + wd->tp[i].guard = 0; + wd->tp[i].code_rate = 0; + wd->tp[i].trans_mode = 0; + + device = malloc(sizeof(char)*40); + snprintf(device,35,"/dev/dvb/adapter%d/mod%d",adapt,i); + fd = open(device, O_RDWR); + if( fd < 0 ) + { + fprintf(stderr,"Error opening %s : %s\n",device,strerror(errno)); + free(device); + exit(1); + } + if (set_property(fd, MODULATOR_FREQUENCY, freq) < 0){ + fprintf(stderr,"setting freq %d failed\n",freq); + exit(1); + } + if (set_property(fd, MODULATOR_MODULATION, qam) < 0){ + fprintf(stderr,"setting qam %d failed\n",qam); + exit(1); + } + if (set_property(fd, MODULATOR_SYMBOL_RATE, sym) < 0){ + fprintf(stderr,"setting sym %d failed\n",sym); + exit(1); + } + + if (set_input_bitrate(fd, (DEFAULT_BIT_RATE_C << 32)) < 0){ + fprintf(stderr,"setting bitrate %d failed\n", + (int)DEFAULT_BIT_RATE_C); + exit(1); + } + + + if (set_property(fd, MODULATOR_PCR_MODE, 0) < 0){ + fprintf(stderr,"setting pcr mode 0 failed\n"); + exit(1); + } + freq += 8000000; + close(fd); + free(device); + } +} + +//+++++++++++++++++++++++++++++CLI++++++++++++++++++++++++++++++++++++++++ + +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +static void usage(char *progname) +{ + printf ("usage: %s [options] \n\n",progname); + printf ("options:\n"); + printf (" --adapter , -a : adapter number of modulator card (defaults to first found)\n"); + printf (" --mods , -m : number of modulators to use (default all)\n"); + printf (" --file, -i : input filename (default test.ts)\n"); + printf (" --frequency, -f : start frequency in MHz (default DVB_C 114MHz, DVB-T 474MHz)\n"); + printf (" --dvbt, -t : modulator is DVB-T\n"); + printf (" --NIT, -n : write a minimal NIT for faster scan\n"); + printf (" --help, -h : print help message\n"); + printf ("\n"); + printf ("\n"); + exit(1); +} + + +static int parse_cl(int argc, char * const argv[], char **filename, int *chans) +{ + int c; + int fset = 0; + + *filename = strdup("test.ts"); + + writeNIT = 0; + dvbt = 0; + while (1){ + int option_index = 0; + static struct option long_options[] = { + {"help", no_argument , NULL, 'h'}, + {"dvbt", no_argument , NULL, 't'}, + {"NIT", no_argument , NULL, 'n'}, + {"adapter", required_argument , NULL, 'a'}, + {"mods", required_argument , NULL, 'm'}, + {"file", required_argument , NULL, 'i'}, + {"frequency", required_argument , NULL, 'f'}, + {NULL, 0, NULL, 0} + }; + + c = getopt_long (argc, argv, "ha:i:f:ntm:",long_options, + &option_index); + + if (c == -1) + break; + + switch (c){ + case 'a': + adapt = (int)strtol(optarg,(char **)NULL, 0); + break; + + case 'm': + *chans = (int)strtol(optarg,(char **)NULL, 0); + break; + + case 'f': + fset = 1; + start_freq = strtoul(optarg, NULL, 0)*1000000; + break; + + case 'i': + if (*filename){ + free(*filename); + } + *filename = strdup(optarg); + break; + + case 'n': + writeNIT = 1; + break; + + case 't': + if (!fset) start_freq = START_FREQ_T; + dvbt = 1; + break; + + case 'h': + case '?': + default: + usage(argv[0]); + + } + } + + return adapt; + +} +//++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +//++++++++++++++++++++++++++++++++++++MAIN++++++++++++++++++++++++++++++++ + +int main(int argc, char **argv) +{ + const char *progn = "modtest"; + + int maxout = 0; + int mods = 0; + char *filename; + char *device; + dvb_devices ddevices; + write_data wd; + int fd_out; + int fd_in; + int chans = 0; + + printf("%s \n\n", progn); + adapt = parse_cl(argc, argv, &filename, &chans); + if (check_dvb(&ddevices)<0){ + fprintf(stderr,"No DVB devices found\n"); + exit(1); + } + + for (int i=0; iddevices.ndevs[adapt] ) + chans = ddevices.ndevs[adapt]; + + if (dvbt){ + set_dvbt_mods(adapt, chans, start_freq, &wd); + } else { + set_dvbc_mods(adapt, chans, start_freq, &wd); + } + + fprintf(stderr,"Reading from %s\n", filename); + device = malloc(sizeof(char)*40); + for (int m= 0; m < chans; m++){ + snprintf(device,35,"/dev/dvb/adapter%d/mod%d",adapt,m); + fd_out = open(device, O_WRONLY); + wd.fd_out[m] = fd_out; + wd.fd_in = fd_in; + wd.name = filename; + } + write_mods(&wd); + + exit(0); +} diff --git a/apps/modulator.conf b/apps/modulator.conf new file mode 100644 index 0000000..1f4cf5c --- /dev/null +++ b/apps/modulator.conf @@ -0,0 +1,51 @@ +[output] +# connector = OFF, SMA or F +connector = F +# number of total channels to be used at the same time +# use lower number to have fewer channels but stronger signal per channel +channels = 16 +# unit of power in DBUV or DBM +unit = DBUV +# power output in units of above unit +power = 50.0 + + +# define channels: +# channels are frequency slots to which a stream (mod0, mod1 ...) can be assigned + +[channels] +# standard: 0 = generic, 1 = DVB-T 8MHz, 2 = DVB-T 7 MHz, 3 = DVB-T 6 MHz +standard = 1 + +# numbers of channels to allocate, starting from frequency below +# this defines 25 channels at 474, 474+8, 474+16, etc. Mhz +channels = 25 +# frequency of channel 0, following channels are spaced according to set standard +frequency = 474.0 + + +[streams] +# number of streams depends on the card hardware +# streams correspond to devices mod0, mod1, ... +# channels are defined above in channels section + +# 0 = 1/32, 1 = 1/16, 2 = 1/8, 3 = 1/4 +guard_interval = 0 +# 0 = 2K, 1 = 8K (2K not yet supported) +fft_size = 1 + +# all following streams will be set according to the last set other parameters + +# example: +# this would set mod 1 to 474 MHz and mod0 to 482 MHz (474 + 8 MHz) +# both with guard interval 1/32 and 8K FFT +# and mod2 to 490MHz, guard interval 1/16 and 8K FFT +channel = 1 +stream = 0 +# +channel = 0 +stream = 1 +# +guard_interval = 1 +channel = 2 +stream = 2 diff --git a/apps/octonet/Makefile b/apps/octonet/Makefile index 0d29c03..7b8a469 100644 --- a/apps/octonet/Makefile +++ b/apps/octonet/Makefile @@ -1,10 +1,11 @@ -all: ddtest octonet octokey ddflash +all: ddtest octonet octokey ddflash ddupdate install: all install -m 0755 ddtest $(DESTDIR)/usr/bin install -m 0755 octonet $(DESTDIR)/usr/bin install -m 0755 octokey $(DESTDIR)/usr/bin install -m 0755 ddflash $(DESTDIR)/usr/bin + install -m 0755 ddupdate $(DESTDIR)/usr/bin ddflash: ddflash.c flash.h flash.c $(CC) -o ddflash ddflash.c @@ -12,6 +13,9 @@ ddflash: ddflash.c flash.h flash.c ddtest: ddtest.c flash.h flash.c $(CC) -o ddtest ddtest.c +ddupdate: ddupdate.c flash.h flash.c + $(CC) -o ddupdate ddupdate.c + octonet: octonet.c $(CC) -o octonet octonet.c diff --git a/apps/octonet/ddflash.c b/apps/octonet/ddflash.c index 3d32c42..5841944 100644 --- a/apps/octonet/ddflash.c +++ b/apps/octonet/ddflash.c @@ -38,25 +38,6 @@ #include "flash.h" #include "flash.c" -static int reboot(uint32_t off) -{ - FILE *f; - uint32_t time; - - if ((f = fopen ("/sys/class/rtc/rtc0/since_epoch", "r")) == NULL) - return -1; - fscanf(f, "%u", &time); - fclose(f); - - if ((f = fopen ("/sys/class/rtc/rtc0/wakealarm", "r+")) == NULL) - return -1; - fprintf(f, "%u", time + off); - fclose(f); - system("/sbin/poweroff"); - return 0; -} - - static int update_flash(struct ddflash *ddf) { char *fname; diff --git a/apps/octonet/ddtest.c b/apps/octonet/ddtest.c index 79d0d1f..4b0c871 100644 --- a/apps/octonet/ddtest.c +++ b/apps/octonet/ddtest.c @@ -405,6 +405,9 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags) case SPANSION_S25FL132K: SectorSize = 4096; FlashSize = 0x400000; break; case SPANSION_S25FL164K: SectorSize = 4096; FlashSize = 0x800000; break; case WINBOND_W25Q16JV: SectorSize = 4096; FlashSize = 0x200000; break; + case WINBOND_W25Q32JV: SectorSize = 4096; FlashSize = 0x400000; break; + case WINBOND_W25Q64JV: SectorSize = 4096; FlashSize = 0x800000; break; + case WINBOND_W25Q128JV: SectorSize = 4096; FlashSize = 0x1000000; break; } if (SectorSize == 0) return 0; @@ -575,6 +578,9 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags) case SPANSION_S25FL132K: case SPANSION_S25FL164K: case WINBOND_W25Q16JV: + case WINBOND_W25Q32JV: + case WINBOND_W25Q64JV: + case WINBOND_W25Q128JV: err = FlashWritePageMode(dev,FlashOffset,Buffer,BufferSize,0x1C); break; } @@ -1331,6 +1337,9 @@ int read_id(int dev, int argc, char* argv[], uint32_t Flags) switch(Flash) { case WINBOND_W25Q16JV: + case WINBOND_W25Q32JV: + case WINBOND_W25Q64JV: + case WINBOND_W25Q128JV: read_winbd(dev, Id); len = 8; break; diff --git a/apps/octonet/ddupdate.c b/apps/octonet/ddupdate.c index 82a2b91..d010eab 100644 --- a/apps/octonet/ddupdate.c +++ b/apps/octonet/ddupdate.c @@ -11,7 +11,6 @@ #include #include - #include "flash.h" #include "flash.c" @@ -115,12 +114,12 @@ static int update_flash(struct ddflash *ddf) if (!fname) fname = default_fname; if (name) - printf("Card: %s\n", 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) + printf("Flash: %s\n", ddf->flash_name); + printf("Version: %08x\n", ddf->id.hw); + printf("REGMAP : %08x\n", ddf->id.regmap); + if ((res = update_image(ddf, fname, 0x10000, ddf->size / 2, 1, 0)) == 1) stat |= 1; return stat; } @@ -142,7 +141,7 @@ static int update_link(struct ddflash *ddf) return ret; } -static int update_card(int ddbnum, char *fname) +static int update_card(int ddbnum, char *fname, int force) { struct ddflash ddf; char ddbname[80]; @@ -156,6 +155,7 @@ static int update_card(int ddbnum, char *fname) ddf.fd = ddb; ddf.link = 0; ddf.fname = fname; + ddf.force = force; links = 1; for (link = 0; link < links; link++) { @@ -200,24 +200,27 @@ static int usage() "-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" + "-f \n force update\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; + int ddbnum = -1, all = 0, i, force = 0, reboot_len = -1; char *fname = 0; + int ret; while (1) { int option_index = 0; int c; static struct option long_options[] = { + {"reboot", optional_argument , NULL, 'r'}, {"help", no_argument , NULL, 'h'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, - "n:havfb:", + "n:havfb:r::", long_options, &option_index); if (c==-1) break; @@ -232,12 +235,23 @@ int main(int argc, char **argv) case 'a': all = 1; break; + case 'f': + force = 1; + break; case 'v': verbose++; break; + case 'r': + if (optarg) + reboot_len = strtol(optarg, NULL, 0); + else + reboot_len = 40; + if (!reboot_len) + reboot(40); + break; case 'h': usage(); - break; + return 0; default: break; @@ -253,17 +267,19 @@ int main(int argc, char **argv) } 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); - } + ret = update_card(ddbnum, fname, force); + else + for (i = 0; i < 100; i++) { + ret = update_card(i, 0, 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); + } + if (reboot_len > 0) + reboot(reboot_len); return 0; } diff --git a/apps/octonet/flash.c b/apps/octonet/flash.c index adad2fc..8a6fb75 100644 --- a/apps/octonet/flash.c +++ b/apps/octonet/flash.c @@ -1,7 +1,28 @@ +static int reboot(uint32_t off) +{ + FILE *f; + uint32_t time; + + if ((f = fopen ("/sys/class/rtc/rtc0/since_epoch", "r")) == NULL) + return -1; + fscanf(f, "%u", &time); + fclose(f); + + if ((f = fopen ("/sys/class/rtc/rtc0/wakealarm", "r+")) == NULL) + return -1; + fprintf(f, "%u", time + off); + fclose(f); + system("/sbin/poweroff"); + return 0; +} + + + static uint32_t linknr = 0; int flashio(int ddb, int link, - uint8_t *wbuf, uint32_t wlen, uint8_t *rbuf, uint32_t rlen) + uint8_t *wbuf, uint32_t wlen, + uint8_t *rbuf, uint32_t rlen) { struct ddb_flashio fio = { .write_buf=wbuf, @@ -29,15 +50,15 @@ struct flash_info flashs[] = { { { 0x01, 0x40, 0x15 }, SPANSION_S25FL116K, 4096, 0x200000, "SPANSION S25FL116K 16 MBit" }, { { 0x01, 0x40, 0x16 }, SPANSION_S25FL132K, 4096, 0x400000, "SPANSION S25FL132K 32 MBit" }, { { 0x01, 0x40, 0x17 }, SPANSION_S25FL164K, 4096, 0x800000, "SPANSION S25FL164K 64 MBit" }, - { { 0xef, 0x40, 0x15 }, WINBOND_W25Q16JV, 4096, 0x200000, "Winbond 16 MBit" }, - { { 0xef, 0x40, 0x16 }, WINBOND_W25Q32JV, 4096, 0x400000, "Winbond 32 MBit" }, - { { 0xef, 0x40, 0x17 }, WINBOND_W25Q64JV, 4096, 0x800000, "Winbond 64 MBit" }, - { { 0xef, 0x40, 0x18 }, WINBOND_W25Q128JV, 4096, 0x1000000, "Winbond 128 MBit" }, - { { 0xef, 0x70, 0x15 }, WINBOND_W25Q16JV, 4096, 0x200000, "Winbond 16 MBit" }, - { { 0xef, 0x70, 0x16 }, WINBOND_W25Q32JV, 4096, 0x400000, "Winbond 32 MBit" }, - { { 0xef, 0x70, 0x17 }, WINBOND_W25Q64JV, 4096, 0x800000, "Winbond 64 MBit" }, - { { 0xef, 0x70, 0x18 }, WINBOND_W25Q128JV, 4096, 0x1000000, "Winbond 128 MBit" }, - { { 0x1f, 0x28, 0xff }, ATMEL_AT45DB642D, 1024, 0x800000, "Atmel AT45DB642D 64 MBit" }, + { { 0xef, 0x40, 0x15 }, WINBOND_W25Q16JV, 4096, 0x200000, "Winbond W25Q16JV 16 MBit" }, + { { 0xef, 0x40, 0x16 }, WINBOND_W25Q32JV, 4096, 0x400000, "Winbond W25Q32JV 32 MBit" }, + { { 0xef, 0x40, 0x17 }, WINBOND_W25Q64JV, 4096, 0x800000, "Winbond W25Q64JV 64 MBit" }, + { { 0xef, 0x40, 0x18 }, WINBOND_W25Q128JV, 4096, 0x1000000, "Winbond W25Q128JV 128 MBit" }, + { { 0xef, 0x70, 0x15 }, WINBOND_W25Q16JV, 4096, 0x200000, "Winbond W25Q16JV 16 MBit" }, + { { 0xef, 0x70, 0x16 }, WINBOND_W25Q32JV, 4096, 0x400000, "Winbond W25Q32JV 32 MBit" }, + { { 0xef, 0x70, 0x17 }, WINBOND_W25Q64JV, 4096, 0x800000, "Winbond W25Q64JV 64 MBit" }, + { { 0xef, 0x70, 0x18 }, WINBOND_W25Q128JV, 4096, 0x1000000, "Winbond W25Q128JV 128 MBit" }, + { { 0x1f, 0x28, 0xff }, ATMEL_AT45DB642D, 1024, 0x800000, "Atmel AT45DB642D 64 MBit" }, { { 0x00, 0x00, 0x00 }, UNKNOWN_FLASH, 0, 0, "Unknown" }, }; @@ -47,7 +68,7 @@ static struct flash_info *flash_getinfo(uint8_t *id) while (f->id[0]) { if ((f->id[0] == id[0]) && (f->id[1] == id[1]) && - ((id[0] == 0xff) || (f->id[0] == id[0]))) + ((id[2] == 0xff) || (f->id[2] == id[2]))) break; f++; } @@ -118,7 +139,7 @@ int flashread(int ddb, int link, uint8_t *buf, uint32_t addr, uint32_t len) uint32_t l; while (len) { - cmd[0] = 3; + cmd[0] = 0x03; cmd[1] = (addr >> 16) & 0xff; cmd[2] = (addr >> 8) & 0xff; cmd[3] = addr & 0xff; @@ -137,12 +158,12 @@ int flashread(int ddb, int link, uint8_t *buf, uint32_t addr, uint32_t len) return 0; } #else -static int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len) +static int flashread(int ddb, int link, uint8_t *buf, uint32_t addr, uint32_t len) { - uint8_t cmd[4]= {0x03, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff}; + uint8_t cmd[5]= {0x0b, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff, 0x00}; - return flashio(ddb, linknr, cmd, 4, buf, len); + return flashio(ddb, link, cmd, 5, buf, len); } #endif @@ -500,10 +521,10 @@ int FlashWritePageMode(int dev, uint32_t FlashOffset, uint8_t Cmd[260]; int i, j; - if( (BufferSize % 4096) != 0 ) return -1; // Must be multiple of sector size + if ((BufferSize % 4096)) + return -1; // Must be multiple of sector size - do - { + do { Cmd[0] = 0x50; // EWSR err = flashio(dev,linknr, Cmd,1,NULL,0); if( err < 0 ) break; @@ -513,8 +534,7 @@ int FlashWritePageMode(int dev, uint32_t FlashOffset, err = flashio(dev,linknr, Cmd,2,NULL,0); if( err < 0 ) break; - for(i = 0; i < BufferSize; i += 4096 ) - { + for(i = 0; i < BufferSize; i += 4096 ) { if( (i & 0xFFFF) == 0 ) { printf(" Erase %08x\n",FlashOffset + i); @@ -588,124 +608,117 @@ int FlashWritePageMode(int dev, uint32_t FlashOffset, return err; } +static int flash_wait(int fd, uint32_t link) +{ + while (1) { + uint8_t rcmd = 0x05; // RDSR + int err = flashio(fd, link, &rcmd, 1, &rcmd, 1); + + if (err < 0) + return err; + if ((rcmd & 0x01) == 0) + break; + } + return 0; +} + + int flashwrite_pagemode(struct ddflash *ddf, int dev, uint32_t FlashOffset, - uint8_t LockBits, uint32_t fw_off) + uint8_t LockBits, uint32_t fw_off, int be) { int err = 0; uint8_t cmd[260]; int i, j; uint32_t flen, blen; + int blockerase = be && ((FlashOffset & 0xFFFF) == 0 ) && (flen >= 0x10000); 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, ddf->link, cmd, 1, NULL, 0); - if (err < 0) - break; - - cmd[0] = 0x01; // WRSR - cmd[1] = 0x00; // BPx = 0, Unlock all blocks - err = flashio(ddf->fd, ddf->link, 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, ddf->link, 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, ddf->link, cmd, 4, NULL, 0); - if (err < 0) - break; + //printf("blen = %u, flen = %u\n", blen, flen); + setbuf(stdout, NULL); - while (1) { - cmd[0] = 0x05; // RDSR - err = flashio(ddf->fd, ddf->link, 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(" Program %08x\n", FlashOffset + j); - - cmd[0] = 0x06; // WREN - err = flashio(ddf->fd, ddf->link, 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, ddf->link, cmd, 260, NULL, 0); - if (err < 0) - break; - - while(1) { - cmd[0] = 0x05; // RDRS - err = flashio(ddf->fd, ddf->link, 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 + cmd[0] = 0x50; // EWSR + err = flashio(ddf->fd, ddf->link, cmd, 1, NULL, 0); + if (err < 0) + return err; + + cmd[0] = 0x01; // WRSR + cmd[1] = 0x00; // BPx = 0, Unlock all blocks + err = flashio(ddf->fd, ddf->link, cmd, 2, NULL, 0); + if (err < 0) + return err; + + for (i = 0; i < flen; ) { + printf(" Erase %08x\r", FlashOffset + i); + cmd[0] = 0x06; // WREN err = flashio(ddf->fd, ddf->link, cmd, 1, NULL, 0); if (err < 0) - break; + return err; + cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF ); + cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF ); + cmd[3] = 0x00; + if (blockerase && ((flen - i) >= 0x10000) ) { + cmd[0] = 0xd8; + i += 0x10000; + } else { + cmd[0] = 0x20; // Sector erase ( 4Kb) + i += 0x1000; + } + err = flashio(ddf->fd, ddf->link, cmd, 4, NULL, 0); + if (err < 0) + return err; + err = flash_wait(ddf->fd, ddf->link); + if (err < 0) + return err; + } + for (j = blen - 256; j >= 0; j -= 256 ) { + uint32_t len = 256; + ssize_t rlen; - cmd[0] = 0x01; // WRSR - cmd[1] = LockBits; // BPx = 0, Lock all blocks - err = flashio(ddf->fd, ddf->link, cmd, 2, NULL, 0); - } while(0); + 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(" Program %08x\r", FlashOffset + j); + + cmd[0] = 0x06; // WREN + err = flashio(ddf->fd, ddf->link, cmd, 1, NULL, 0); + if (err < 0) + goto out; + + 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, ddf->link, cmd, 260, NULL, 0); + if (err < 0) + goto out; + err = flash_wait(ddf->fd, ddf->link); + if (err < 0) + goto out; + } + printf("\n"); + + cmd[0] = 0x50; // EWSR + err = flashio(ddf->fd, ddf->link, cmd, 1, NULL, 0); + if (err < 0) + goto out; + + cmd[0] = 0x01; // WRSR + cmd[1] = LockBits; // BPx = 0, Lock all blocks + err = flashio(ddf->fd, ddf->link, cmd, 2, NULL, 0); +out: return err; } @@ -845,7 +858,7 @@ static int flashwrite(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxle case SSTI_SST25VF032B: return flashwrite_SSTI(ddf, fs, addr, maxlen, fw_off); case SSTI_SST25VF064C: - return flashwrite_pagemode(ddf, fs, addr, 0x3c, fw_off); + return flashwrite_pagemode(ddf, fs, addr, 0x3c, fw_off, 0); case SPANSION_S25FL116K: case SPANSION_S25FL132K: case SPANSION_S25FL164K: @@ -853,7 +866,8 @@ static int flashwrite(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxle case WINBOND_W25Q32JV: case WINBOND_W25Q64JV: case WINBOND_W25Q128JV: - return flashwrite_pagemode(ddf, fs, addr, 0x1c, fw_off); + default: + return flashwrite_pagemode(ddf, fs, addr, 0x1c, fw_off, 1); } return -1; } @@ -892,97 +906,55 @@ static int get_id(struct ddflash *ddf) return 0; } +struct devids { + uint16_t id; + char *name; + char *fname; +}; + +#define DEV(_id, _name, _fname) { .id = _id, .name = _name, .fname = _fname } + +static const struct devids ids[] = { + DEV(0x0002, "Octopus 35", "DVBBridgeV1A_DVBBridgeV1A.bit"), + DEV(0x0003, "Octopus", "DVBBridgeV1B_DVBBridgeV1B.fpga"), + DEV(0x0005, "Octopus Classic", "DVBBridgeV2A_DD01_0005_STD.fpga"), + DEV(0x0006, "CineS2 V7", "DVBBridgeV2A_DD01_0006_STD.fpga"), + DEV(0x0007, "Octopus 4/8", "DVBBridgeV2A_DD01_0007_MXL.fpga"), + DEV(0x0008, "Octopus 4/8", "DVBBridgeV2A_DD01_0008_CXD.fpga"), + DEV(0x0009, "Octopus MAXSX8", "DVBBridgeV2A_DD01_0009_SX8.fpga"), + DEV(0x000b, "Octopus MAXSX8 Basic", "DVBBridgeV2A_DD01_000B_SX8.fpga"), + DEV(0x000a, "Octopus MAXM4", "DVBBridgeV2A_DD01_000A_M4.fpga"), + DEV(0x0011, "Octopus CI", "DVBBridgeV2B_DD01_0011.fpga"), + DEV(0x0012, "Octopus CI", "DVBBridgeV2B_DD01_0012_STD.fpga"), + DEV(0x0013, "Octopus PRO", "DVBBridgeV2B_DD01_0013_PRO.fpga"), + DEV(0x0020, "Octopus GT Mini", "DVBBridgeV2C_DD01_0020.fpga"), + DEV(0x0201, "Modulator", "DVBModulatorV1B_DVBModulatorV1B.bit"), + DEV(0x0203, "Modulator Test", "DVBModulatorV1B_DD01_0203.fpga"), + DEV(0x0210, "Modulator V2", "DVBModulatorV2A_DD01_0210.fpga"), + DEV(0x0220, "SDRModulator ATV", "SDRModulatorV1A_DD01_0220.fpga"), + DEV(0x0221, "SDRModulator IQ", "SDRModulatorV1A_DD01_0221_IQ.fpga"), + DEV(0x0222, "SDRModulator DVBT", "SDRModulatorV1A_DD01_0222_DVBT.fpga"), + DEV(0x0223, "SDRModulator IQ2", "SDRModulatorV1A_DD01_0223_IQ2.fpga"), + DEV(0x0000, "UNKNOWN", 0), +}; static char *devid2fname(uint16_t devid, char **name) { + int i; char *fname = 0; - switch (devid) { - case 0x0002: - fname="DVBBridgeV1A_DVBBridgeV1A.bit"; - *name = "Octopus 35"; - break; - case 0x0003: - fname="DVBBridgeV1B_DVBBridgeV1B.fpga"; - *name = "Octopus"; - break; - case 0x0005: - fname="DVBBridgeV2A_DD01_0005_STD.fpga"; - *name = "Octopus Classic"; - break; - case 0x0006: - fname="DVBBridgeV2A_DD01_0006_STD.fpga"; - *name = "CineS2 V7"; - break; - case 0x0007: - fname="DVBBridgeV2A_DD01_0007_MXL.fpga"; - *name = "Octopus 4/8"; - break; - case 0x0008: - fname="DVBBridgeV2A_DD01_0008_CXD.fpga"; - *name = "Octopus 4/8"; - break; - case 0x0009: - fname="DVBBridgeV2A_DD01_0009_SX8.fpga"; - *name = "Octopus MAXSX8"; - break; - case 0x000b: - fname="DVBBridgeV2A_DD01_000B_SX8.fpga"; - *name = "Octopus MAXSX8 Basic"; - break; - case 0x000a: - fname="DVBBridgeV2A_DD01_000A_M4.fpga"; - *name = "Octopus MAXM4"; - break; - case 0x0011: - fname="DVBBridgeV2B_DD01_0011.fpga"; - *name = "Octopus CI"; - break; - case 0x0012: - fname="DVBBridgeV2B_DD01_0012_STD.fpga"; - *name = "Octopus CI"; - break; - case 0x0013: - fname="DVBBridgeV2B_DD01_0013_PRO.fpga"; - *name = "Octopus PRO"; - break; - case 0x0020: - fname="DVBBridgeV2C_DD01_0020.fpga"; - *name = "Octopus GT Mini"; - break; - case 0x0201: - fname="DVBModulatorV1B_DVBModulatorV1B.bit"; - *name = "Modulator"; - break; - case 0x0203: - fname="DVBModulatorV1B_DD01_0203.fpga"; - *name = "Modulator Test"; - break; - case 0x0210: - fname="DVBModulatorV2A_DD01_0210.fpga"; - *name = "Modulator V2"; - break; - case 0x0220: - fname="SDRModulatorV1A_DD01_0220.fpga"; - *name = "SDRModulator ATV"; - break; - case 0x0221: - fname="SDRModulatorV1A_DD01_0221_IQ.fpga"; - *name = "SDRModulator IQ"; - break; - case 0x0222: - fname="SDRModulatorV1A_DD01_0222_DVBT.fpga"; - *name = "SDRModulator DVBT"; - break; - default: - *name = "UNKNOWN"; - break; + for (i = 0; ; i++) { + const struct devids *id = &ids[i]; + + if (devid == id->id || !id->id) { + *name = id->name; + fname = id->fname; + break; + } } return fname; } - - static int flashcmp(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, uint32_t fw_off) { off_t off; @@ -996,12 +968,10 @@ static int flashcmp(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, return -1; len = off - fw_off; lseek(fs, fw_off, SEEK_SET); -#if 0 if (len > maxlen) { printf("file too big\n"); return -1; } -#endif //printf("flash file len %u, compare to %08x in flash: ", len, addr); for (j = 0; j < len; j += bl, addr += bl) { if (len - j < bl) @@ -1015,9 +985,9 @@ static int flashcmp(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, if (memcmp(buf, buf2, bl)) { printf("flash differs at %08x (offset %u)\n", addr, j); - dump(buf, bl); - printf("\n"); - dump(buf2, bl); + //dump(buf, bl); + //printf("\n"); + //dump(buf2, bl); return addr; } } @@ -1080,7 +1050,7 @@ static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off) unsigned int devid, version, length; unsigned int cid[8]; int cids = 0; - uint32_t maxlen = 2 * 1024 * 1024, crc; + uint32_t maxlen = 2 * 1024 * 1024, crc, fcrc; fd = open(fn, O_RDONLY); if (fd < 0) { @@ -1148,15 +1118,27 @@ static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off) } p++; *fw_off = p; - printf(" CRC = %08x\n", crc); - printf(" devid = %04x\n", devid); - printf(" version = %08x (current image = %08x)\n", version, ddf->id.hw); + fcrc = crc32(buf + p, length, 0xffffffff); + printf(" CRC file = %08x\n", fcrc); + printf(" CRC flash = %08x\n", crc); + printf(" devid = %04x\n", devid); + printf(" version = %08x (current image = %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 (fcrc != crc) { + printf("CRC error in file %s!\n", fn); + return -4; + } if (devid == ddf->id.device) { - if (version <= (ddf->id.hw & 0xffffff)) { - printf("%s is older or same version as flash\n", fn); - ret = -3; /* same id but no newer version */ + if (version < (ddf->id.hw & 0xffffff)) { + printf("%s is older version than flash\n", fn); + if (!ddf->force) + ret = -3; /* same id but older newer version */ + } + if (version == (ddf->id.hw & 0xffffff)) { + printf("%s is same version as flash\n", fn); + if (!ddf->force) + ret = 2; /* same and same version */ } } else ret = 1; @@ -1169,13 +1151,13 @@ out: } static int update_image(struct ddflash *ddf, char *fn, - uint32_t adr, uint32_t len, + uint32_t adr, uint32_t maxlen, int has_header, int no_change) { int fs, res = 0; uint32_t fw_off = 0; - printf("File: %s\n", fn); + printf("File: %s\n", fn); if (has_header) { int ck; ck = check_fw(ddf, fn, &fw_off); @@ -1189,17 +1171,24 @@ static int update_image(struct ddflash *ddf, char *fn, printf("File %s not found \n", fn); return -1; } - res = flashcmp(ddf, fs, adr, len, fw_off); + res = flashcmp(ddf, fs, adr, maxlen, fw_off); if (res == -2) { printf("Flash already identical to %s\n", fn); + if (ddf->force) { + printf("but force enabled!\n"); + res = 0; + } } if (res < 0) goto out; - res = flashwrite(ddf, fs, adr, len, fw_off); + res = flashwrite(ddf, fs, adr, maxlen, fw_off); if (res == 0) { - res = flashcmp(ddf, fs, adr, len, fw_off); + res = flashcmp(ddf, fs, adr, maxlen, fw_off); if (res == -2) { res = 1; + printf("Flash verify OK!\n"); + } else { + printf("Flash verify ERROR!\n"); } } diff --git a/apps/octonet/flash.h b/apps/octonet/flash.h index 350fabe..8271be0 100644 --- a/apps/octonet/flash.h +++ b/apps/octonet/flash.h @@ -89,6 +89,7 @@ struct ddflash { int fd; uint32_t link; char *fname; + int force; struct ddb_id id; uint32_t version; diff --git a/apps/pls.c b/apps/pls.c index 510b1b2..b21ca59 100644 --- a/apps/pls.c +++ b/apps/pls.c @@ -147,7 +147,7 @@ int main(int argc, char **argv) if (gold != 0xffffffff) { if (gold < 0x3ffff) { root = gold2root(gold); - printf("gold = %llu (0x%05x) root = %llu (0x%05x)\n", + printf("gold = %u (0x%05x) root = %u (0x%05x)\n", gold, gold, root, root); } else printf("Invalid gold code specified.\n"); diff --git a/apps/setmod3.c b/apps/setmod3.c index 1b99b18..fb83015 100644 --- a/apps/setmod3.c +++ b/apps/setmod3.c @@ -58,7 +58,7 @@ int main(int argc, char*argv[]) struct dvb_mod_params mp; struct dvb_mod_channel_params mc; uint32_t data; - int adapter = 0, channel = 0, gain = -1; + int32_t adapter = 0, channel = 0, gain = -1; int32_t base = -1, freq = -1, rate = -1; char mod_name[128]; @@ -113,7 +113,7 @@ int main(int argc, char*argv[]) } } if (optind < argc) { - printf("too man arguments\n"); + printf("too many arguments\n"); exit(1); } @@ -134,6 +134,8 @@ int main(int argc, char*argv[]) //get_property(fd, MODULATOR_ATTENUATOR, &data); //printf("Modulator attenuator = %u\n", data); + if (gain > 0) + set_property(fd, MODULATOR_GAIN, gain); if (base > 0) set_property(fd, MODULATOR_BASE_FREQUENCY, base); if (freq > 0) diff --git a/apps/tscheck.c b/apps/tscheck.c index ea132c8..f3947eb 100644 --- a/apps/tscheck.c +++ b/apps/tscheck.c @@ -27,14 +27,16 @@ 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)) ) + if ((((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) ) { cc_errors += 1; + printf("%04x: %u != %u\n", pid, (cc[pid] + 1) & 0x0F, ccin & 0x0F); + } } cc[pid] = ccin; } diff --git a/ddbridge/Kbuild b/ddbridge/Kbuild index bc9c7c5..cec6ff1 100644 --- a/ddbridge/Kbuild +++ b/ddbridge/Kbuild @@ -1,12 +1,16 @@ EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843 -DCONFIG_DVB_LNBP21 -DCONFIG_DVB_STV090x -DCONFIG_DVB_STV6110x -DCONFIG_DVB_DRXK -DCONFIG_DVB_STV0910 -DCONFIG_DVB_STV6111 -DCONFIG_DVB_LNBH25 -DCONFIG_DVB_MXL5XX -DCONFIG_DVB_CXD2099 -DCONFIG_DVB_NET 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 #mci-objs = ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o ddbridge-io.o obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o #mci.o + +ifneq ($(KERNEL_DVB_CORE),y) obj-$(CONFIG_DVB_OCTONET) += octonet.o +endif #EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends #EXTRA_CFLAGS += -Idrivers/media/common/tuners diff --git a/ddbridge/Makefile.kernel b/ddbridge/Makefile.kernel index 7a40c24..ff82c71 100644 --- a/ddbridge/Makefile.kernel +++ b/ddbridge/Makefile.kernel @@ -3,7 +3,7 @@ # 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-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 obj-$(CONFIG_DVB_OCTONET) += octonet.o @@ -11,4 +11,5 @@ obj-$(CONFIG_DVB_OCTONET) += octonet.o ccflags-y += -Idrivers/media/dvb-core/ ccflags-y += -Idrivers/media/dvb-frontends/ ccflags-y += -Idrivers/media/tuners/ +ccflags-y += --include=dd_compat.h diff --git a/ddbridge/ddbridge-ci.c b/ddbridge/ddbridge-ci.c index 99d5a1f..365f8fc 100644 --- a/ddbridge/ddbridge-ci.c +++ b/ddbridge/ddbridge-ci.c @@ -105,7 +105,7 @@ static int slot_reset(struct dvb_ca_en50221 *ca, int slot) ddbwritel(ci->port->dev, CI_POWER_ON, CI_CONTROL(ci->nr)); - msleep(100); + msleep(300); ddbwritel(ci->port->dev, CI_POWER_ON | CI_RESET_CAM, CI_CONTROL(ci->nr)); ddbwritel(ci->port->dev, CI_ENABLE | CI_POWER_ON | CI_RESET_CAM, @@ -236,7 +236,7 @@ static int slot_reset_xo2(struct dvb_ca_en50221 *ca, int slot) write_creg(ci, 0x01, 0x01); write_creg(ci, 0x04, 0x04); - msleep(20); + msleep(300); write_creg(ci, 0x02, 0x02); write_creg(ci, 0x00, 0x04); write_creg(ci, 0x18, 0x18); diff --git a/ddbridge/ddbridge-core.c b/ddbridge/ddbridge-core.c index d911837..3c97f27 100644 --- a/ddbridge/ddbridge-core.c +++ b/ddbridge/ddbridge-core.c @@ -24,6 +24,7 @@ #include "ddbridge.h" #include "ddbridge-i2c.h" #include "ddbridge-io.h" +#include "ddbridge-ioctl.h" #include struct workqueue_struct *ddb_wq; @@ -94,6 +95,70 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr); /****************************************************************************/ /****************************************************************************/ +/* copied from dvb-core/dvbdev.c because kernel version does not export it */ + +int ddb_dvb_usercopy(struct file *file, + unsigned int cmd, unsigned long arg, + int (*func)(struct file *file, + unsigned int cmd, void *arg)) +{ + char sbuf[128]; + void *mbuf = NULL; + void *parg = NULL; + int err = -EINVAL; + + /* Copy arguments into temp kernel buffer */ + switch (_IOC_DIR(cmd)) { + case _IOC_NONE: + /* + * For this command, the pointer is actually an integer + * argument. + */ + parg = (void *) arg; + break; + case _IOC_READ: /* some v4l ioctls are marked wrong ... */ + case _IOC_WRITE: + case (_IOC_WRITE | _IOC_READ): + if (_IOC_SIZE(cmd) <= sizeof(sbuf)) { + parg = sbuf; + } else { + /* too big to allocate from stack */ + mbuf = kmalloc(_IOC_SIZE(cmd), GFP_KERNEL); + if (NULL == mbuf) + return -ENOMEM; + parg = mbuf; + } + + err = -EFAULT; + if (copy_from_user(parg, (void __user *)arg, _IOC_SIZE(cmd))) + goto out; + break; + } + + /* call driver */ + if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD) + err = -ENOTTY; + + if (err < 0) + goto out; + + /* Copy results into user buffer */ + switch (_IOC_DIR(cmd)) + { + case _IOC_READ: + case (_IOC_WRITE | _IOC_READ): + if (copy_to_user((void __user *)arg, parg, _IOC_SIZE(cmd))) + err = -EFAULT; + break; + } + +out: + kfree(mbuf); + return err; +} + +/****************************************************************************/ + struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr, void (*handler)(void *), void *data) { @@ -281,9 +346,9 @@ static int dma_alloc(struct pci_dev *pdev, struct ddb_dma *dma, int dir) for (i = 0; i < dma->num; i++) { if (alt_dma) { #if (KERNEL_VERSION(4, 13, 0) > LINUX_VERSION_CODE) - dma->vbuf[i] = kmalloc(dma->size, __GFP_REPEAT); + dma->vbuf[i] = kzalloc(dma->size, __GFP_REPEAT); #else - dma->vbuf[i] = kmalloc(dma->size, __GFP_RETRY_MAYFAIL); + dma->vbuf[i] = kzalloc(dma->size, __GFP_RETRY_MAYFAIL); #endif if (!dma->vbuf[i]) return -ENOMEM; @@ -301,10 +366,12 @@ static int dma_alloc(struct pci_dev *pdev, struct ddb_dma *dma, int dir) dma->vbuf[i] = dma_alloc_coherent(&pdev->dev, dma->size, &dma->pbuf[i], - GFP_KERNEL); + GFP_KERNEL | __GFP_ZERO); if (!dma->vbuf[i]) return -ENOMEM; } + if (((uintptr_t) dma->vbuf[i] & 0xfff)) + dev_err(&pdev->dev, "DMA memory at %px not aligned!\n", dma->vbuf[i]); } return 0; } @@ -333,7 +400,7 @@ static int ddb_buffers_alloc(struct ddb *dev) if (dma_alloc(dev->pdev, port->input[0]->dma, 0) < 0) return -1; - /* fallthrough */ + fallthrough; case DDB_PORT_MOD: if (port->output->dma) if (dma_alloc(dev->pdev, @@ -454,10 +521,11 @@ static void calc_con(struct ddb_output *output, u32 *con, u32 *con2, u32 flags) *con2 = (nco << 16) | gap; } -static void ddb_output_start_unlocked(struct ddb_output *output) +static int ddb_output_start_unlocked(struct ddb_output *output) { struct ddb *dev = output->port->dev; u32 con = 0x11c, con2 = 0; + int err = 0; if (output->dma) { output->dma->cbuf = 0; @@ -466,7 +534,9 @@ static void ddb_output_start_unlocked(struct ddb_output *output) ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma)); } if (output->port->class == DDB_PORT_MOD) { - ddbridge_mod_output_start(output); +#ifndef CONFIG_MACH_OCTONET + err = ddbridge_mod_output_start(output); +#endif } else { if (output->port->input[0]->port->class == DDB_PORT_LOOP) con = (1UL << 13) | 0x14; @@ -489,26 +559,32 @@ static void ddb_output_start_unlocked(struct ddb_output *output) ddbwritel(dev, con | 1, TS_CONTROL(output)); if (output->dma) output->dma->running = 1; + return err; } -static void ddb_output_start(struct ddb_output *output) +static int ddb_output_start(struct ddb_output *output) { + int err; + if (output->dma) { spin_lock_irq(&output->dma->lock); - ddb_output_start_unlocked(output); + err = ddb_output_start_unlocked(output); spin_unlock_irq(&output->dma->lock); } else { - ddb_output_start_unlocked(output); + err = ddb_output_start_unlocked(output); } + return err; } static void ddb_output_stop_unlocked(struct ddb_output *output) { struct ddb *dev = output->port->dev; +#ifndef CONFIG_MACH_OCTONET if (output->port->class == DDB_PORT_MOD) ddbridge_mod_output_stop(output); else +#endif ddbwritel(dev, 0, TS_CONTROL(output)); if (output->dma) { ddbwritel(dev, 0, DMA_BUFFER_CONTROL(output->dma)); @@ -527,6 +603,18 @@ static void ddb_output_stop(struct ddb_output *output) } } +static void update_loss(struct ddb_dma *dma) +{ + struct ddb_input *input = (struct ddb_input *)dma->io; + u32 packet_loss = dma->packet_loss; + u32 cur_counter = ddbreadl(input->port->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; +} + static void ddb_input_stop_unlocked(struct ddb_input *input) { struct ddb *dev = input->port->dev; @@ -538,11 +626,14 @@ static void ddb_input_stop_unlocked(struct ddb_input *input) input->dma->running = 0; if (input->dma->stall_count) dev_warn(input->port->dev->dev, - "DMA stalled %u times!\n", + "l%ui%u: DMA stalled %u times!\n", + input->port->lnr, input->nr, input->dma->stall_count); - if (input->dma->packet_loss) + update_loss(input->dma); + if (input->dma->packet_loss > 1) dev_warn(input->port->dev->dev, - "%u packets lost due to low DMA performance!\n", + "l%ui%u: %u packets lost due to low DMA performance!\n", + input->port->lnr, input->nr, input->dma->packet_loss); } } @@ -918,7 +1009,7 @@ static int ts_open(struct inode *inode, struct file *file) if ((file->f_flags & O_ACCMODE) == O_RDONLY) ddb_input_start(input); else if ((file->f_flags & O_ACCMODE) == O_WRONLY) - ddb_output_start(output); + err = ddb_output_start(output); return err; } @@ -977,8 +1068,12 @@ static struct dvb_device dvbdev_ci = { static long mod_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return dvb_usercopy(file, cmd, arg, ddbridge_mod_do_ioctl); -} +#ifndef CONFIG_MACH_OCTONET + return ddb_dvb_usercopy(file, cmd, arg, ddbridge_mod_do_ioctl); +#else + return 0; +#endif + } static const struct file_operations mod_fops = { .owner = THIS_MODULE, @@ -1029,13 +1124,19 @@ static void dummy_release(struct dvb_frontend *fe) kfree(fe); } +static enum dvbfe_algo dummy_algo(struct dvb_frontend *fe) +{ + return DVBFE_ALGO_HW; +} + static struct dvb_frontend_ops dummy_ops = { - .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBS, SYS_DVBS2 }, + .delsys = { SYS_DVBC_ANNEX_A }, .info = { - .name = "DUMMY DVB-C/C2 DVB-T/T2", - .frequency_stepsize_hz = 166667, /* DVB-T only */ - .frequency_min_hz = 47000000, /* DVB-T: 47125000 */ - .frequency_max_hz = 865000000, /* DVB-C: 862000000 */ + .name = "DUMMY DVB-C", + .frequency_stepsize_hz = 0, + .frequency_tolerance_hz = 0, + .frequency_min_hz = 47000000, + .frequency_max_hz = 865000000, .symbol_rate_min = 870000, .symbol_rate_max = 11700000, .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | @@ -1048,6 +1149,7 @@ static struct dvb_frontend_ops dummy_ops = { FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION }, + .get_frontend_algo = dummy_algo, .release = dummy_release, .read_status = dummy_read_status, }; @@ -1068,7 +1170,11 @@ static int demod_attach_dummy(struct ddb_input *input) { struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; +#if 0 dvb->fe = dvb_attach(dummy_attach); +#else + dvb->fe = dummy_attach(); +#endif return 0; } @@ -1139,6 +1245,7 @@ static int demod_attach_stv0367dd(struct ddb_input *input) return 0; } +#ifdef CONFIG_DVB_DRXK static int tuner_attach_tda18271(struct ddb_input *input) { struct i2c_adapter *i2c = &input->port->i2c->adap; @@ -1157,6 +1264,7 @@ static int tuner_attach_tda18271(struct ddb_input *input) } return 0; } +#endif static int tuner_attach_tda18212dd(struct ddb_input *input) { @@ -1426,35 +1534,37 @@ static void dvb_input_detach(struct ddb_input *input) case 0x41: if (dvb->fe2) dvb_unregister_frontend(dvb->fe2); - /* fallthrough */ + fallthrough; case 0x40: if (dvb->fe) dvb_unregister_frontend(dvb->fe); - /* fallthrough */ + fallthrough; case 0x30: dvb_frontend_detach(dvb->fe); dvb->fe = NULL; dvb->fe2 = NULL; - /* fallthrough */ + fallthrough; case 0x21: if (input->port->dev->ns_num) dvb_netstream_release(&dvb->dvbns); - /* fallthrough */ + fallthrough; case 0x20: +#ifdef CONFIG_DVB_NET dvb_net_release(&dvb->dvbnet); - /* fallthrough */ +#endif + fallthrough; case 0x12: dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &dvb->hw_frontend); dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &dvb->mem_frontend); - /* fallthrough */ + fallthrough; case 0x11: dvb_dmxdev_release(&dvb->dmxdev); - /* fallthrough */ + fallthrough; case 0x10: dvb_dmx_release(&dvb->demux); - /* fallthrough */ + fallthrough; case 0x01: break; } @@ -1620,9 +1730,11 @@ static int dvb_input_attach(struct ddb_input *input) return ret; dvb->attached = 0x12; +#ifdef CONFIG_DVB_NET ret = dvb_net_init(adap, &dvb->dvbnet, dvb->dmxdev.demux); if (ret < 0) return ret; +#endif dvb->attached = 0x20; if (input->port->dev->ns_num) { @@ -1695,7 +1807,7 @@ static int dvb_input_attach(struct ddb_input *input) osc24 = 0; else osc24 = 1; - /* fallthrough */ + fallthrough; case DDB_TUNER_DVBCT2_SONY_P: case DDB_TUNER_DVBC2T2_SONY_P: case DDB_TUNER_ISDBT_SONY_P: @@ -1712,7 +1824,7 @@ static int dvb_input_attach(struct ddb_input *input) break; case DDB_TUNER_DVBC2T2I_SONY: osc24 = 1; - /* fallthrough */ + fallthrough; case DDB_TUNER_DVBCT2_SONY: case DDB_TUNER_DVBC2T2_SONY: case DDB_TUNER_ISDBT_SONY: @@ -1991,14 +2103,14 @@ static void ddb_port_probe(struct ddb_port *port) return; } - if (port->nr == 1 && dev->link[l].info->type == DDB_OCTOPUS_CI && + if (port->nr == 1 && link->info->type == DDB_OCTOPUS_CI && link->info->i2c_mask == 1) { port->name = "NO TAB"; port->class = DDB_PORT_NONE; return; } - if (dev->link[l].info->type == DDB_MOD) { + if (link->info->type == DDB_MOD) { port->name = "MOD"; port->class = DDB_PORT_MOD; return; @@ -2014,9 +2126,8 @@ static void ddb_port_probe(struct ddb_port *port) return; } - if (link->info->type == DDB_OCTOPUS_MCI) { - if (port->nr >= link->info->mci_ports) - return; + if ((link->info->type == DDB_OCTOPUS_MCI) && + (port->nr < link->info->mci_ports)) { port->name = "DUAL MCI"; port->type_name = "MCI"; port->class = DDB_PORT_TUNER; @@ -2160,7 +2271,7 @@ static int ddb_port_attach(struct ddb_port *port) ret = ddb_ci_attach(port, ci_bitrate); if (ret < 0) break; - /* fallthrough */ + fallthrough; case DDB_PORT_LOOP: ret = dvb_register_device(port->dvb[0].adap, &port->dvb[0].dev, @@ -2277,21 +2388,36 @@ static void input_write_dvb(struct ddb_input *input, } while (dma->cbuf != ((dma->stat >> 11) & 0x1f) || (4 & dma->ctrl)) { if (4 & dma->ctrl) { - /*dev_err(dev->dev, "Overflow dma %d\n", dma->nr);*/ + dev_warn(dev->dev, "Overflow dma input %u\n", input->nr); ack = 1; } if (alt_dma) dma_sync_single_for_cpu(dev->dev, dma2->pbuf[dma->cbuf], dma2->size, DMA_FROM_DEVICE); - if (raw_stream || input->con) + if (raw_stream || input->con) { dvb_dmx_swfilter_raw(&dvb->demux, dma2->vbuf[dma->cbuf], dma2->size); - else - dvb_dmx_swfilter_packets(&dvb->demux, + } else { + if (dma2->unaligned || (dma2->vbuf[dma->cbuf][0] != 0x47)) { + if (!dma2->unaligned) { + dma2->unaligned++; + dev_warn(dev->dev, "Input %u dma buffer unaligned, " + "switching to unaligned processing.\n", + input->nr); + print_hex_dump(KERN_INFO, "TS: ", DUMP_PREFIX_OFFSET, 32, 1, + dma2->vbuf[dma->cbuf], + 512, false); + } + dvb_dmx_swfilter(&dvb->demux, dma2->vbuf[dma->cbuf], - dma2->size / 188); - + dma2->size); + } else + dvb_dmx_swfilter_packets(&dvb->demux, + dma2->vbuf[dma->cbuf], + dma2->size / 188); + } + dma->cbuf = (dma->cbuf + 1) % dma2->num; if (ack) ddbwritel(dev, (dma->cbuf << 11), @@ -2301,15 +2427,9 @@ static void input_write_dvb(struct ddb_input *input, } } -#ifdef DDB_USE_WORK -static void input_work(struct work_struct *work) -{ - struct ddb_dma *dma = container_of(work, struct ddb_dma, work); -#else static void input_tasklet(unsigned long data) { struct ddb_dma *dma = (struct ddb_dma *)data; -#endif struct ddb_input *input = (struct ddb_input *)dma->io; struct ddb *dev = input->port->dev; unsigned long flags; @@ -2321,16 +2441,7 @@ static void input_tasklet(unsigned long data) } dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); - - { - 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; - } + update_loss(dma); if (4 & dma->ctrl) dma->stall_count++; if (input->redi) @@ -2351,17 +2462,10 @@ static void input_handler(unsigned long data) * just copy pointers and ACK. So, there is no need to go * through the tasklet scheduler. */ - #ifdef DDB_USE_WORK - if (input->redi) - queue_work(ddb_wq, &dma->work); - else - input_work(&dma->work); - #else if (input->redi) tasklet_schedule(&dma->tasklet); else input_tasklet(data); - #endif } #else @@ -2370,23 +2474,13 @@ static void input_handler(void *data) struct ddb_input *input = (struct ddb_input *)data; struct ddb_dma *dma = input->dma; -#ifdef DDB_USE_WORK - queue_work(ddb_wq, &dma->work); -#else input_tasklet((unsigned long)dma); -#endif } #endif -#ifdef DDB_USE_WORK -static void output_work(struct work_struct *work) -{ - struct ddb_dma *dma = container_of(work, struct ddb_dma, work); -#else static void output_tasklet(unsigned long data) { struct ddb_dma *dma = (struct ddb_dma *)data; -#endif struct ddb_output *output = (struct ddb_output *)dma->io; struct ddb *dev = output->port->dev; unsigned long flags; @@ -2428,11 +2522,7 @@ static void output_handler(void *data) struct ddb_output *output = (struct ddb_output *)data; struct ddb_dma *dma = output->dma; -#ifdef DDB_USE_WORK - queue_work(ddb_wq, &dma->work); -#else tasklet_schedule(&dma->tasklet); -#endif } #endif @@ -2463,11 +2553,7 @@ static void ddb_dma_init(struct ddb_io *io, int nr, int out, int irq_nr) spin_lock_init(&dma->lock); init_waitqueue_head(&dma->wq); if (out) { -#ifdef DDB_USE_WORK - INIT_WORK(&dma->work, output_work); -#else tasklet_init(&dma->tasklet, output_tasklet, (unsigned long)dma); -#endif dma->regs = rm->odma->base + rm->odma->size * nr; dma->bufregs = rm->odma_buf->base + rm->odma_buf->size * nr; if (io->port->dev->link[0].info->type == DDB_MOD && @@ -2481,11 +2567,7 @@ static void ddb_dma_init(struct ddb_io *io, int nr, int out, int irq_nr) dma->div = 1; } } else { -#ifdef DDB_USE_WORK - INIT_WORK(&dma->work, input_work); -#else tasklet_init(&dma->tasklet, input_tasklet, (unsigned long)dma); -#endif dma->regs = rm->idma->base + rm->idma->size * nr; dma->bufregs = rm->idma_buf->base + rm->idma_buf->size * nr; dma->num = dma_buf_num; @@ -2507,8 +2589,10 @@ static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr) rm = io_regmap(input, 1); input->regs = DDB_LINK_TAG(port->lnr) | (rm->input->base + rm->input->size * nr); +#if 0 dev_info(dev->dev, "init link %u, input %u, regs %08x\n", port->lnr, nr, input->regs); +#endif if (dev->has_dma) { const struct ddb_regmap *rm0 = io_regmap(input, 0); u32 base = rm0->irq_base_idma; @@ -2574,7 +2658,7 @@ static int ddb_port_match_link_i2c(struct ddb_port *port) static void ddb_ports_init(struct ddb *dev) { - u32 i, l, p; + u32 i, l, p, ports; struct ddb_port *port; const struct ddb_info *info; const struct ddb_regmap *rm; @@ -2586,7 +2670,8 @@ static void ddb_ports_init(struct ddb *dev) rm = info->regmap; if (!rm) continue; - for (i = 0; i < info->port_num; i++, p++) { + ports = info->port_num; + for (i = 0; i < ports; i++, p++) { port = &dev->port[p]; port->dev = dev; port->nr = i; @@ -2608,6 +2693,7 @@ static void ddb_ports_init(struct ddb *dev) port->class = DDB_PORT_CI; port->type = DDB_CI_EXTERNAL_XO2_B; port->name = "DuoFlex CI_B"; + port->type_name = "CI_XO2_B"; port->i2c = dev->port[p - 1].i2c; } dev_info(dev->dev, "Port %u: Link %u, Link Port %u (TAB %u): %s\n", @@ -2629,15 +2715,16 @@ static void ddb_ports_init(struct ddb *dev) } if (port->class == DDB_PORT_NONE) continue; - - switch (dev->link[l].info->type) { + + switch (info->type) { case DDB_OCTOPUS_CI: if (i >= 2) { ddb_input_init(port, 2 + i, 0, 2 + i); ddb_input_init(port, 4 + i, 1, 4 + i); ddb_output_init(port, i); break; - } /* fallthrough */ + } + fallthrough; case DDB_OCTONET: case DDB_OCTOPUS: case DDB_OCTOPRO: @@ -2652,10 +2739,12 @@ static void ddb_ports_init(struct ddb *dev) ddb_input_init(port, 2 * i + 1, 1, 2 * p + 1); break; case DDB_MOD: +#ifndef CONFIG_MACH_OCTONET ddb_output_init(port, i); ddb_irq_set(dev, 0, i + rm->irq_base_rate, &ddbridge_mod_rate_handler, &dev->output[i]); +#endif break; default: break; @@ -2672,21 +2761,12 @@ void ddb_ports_release(struct ddb *dev) for (i = 0; i < dev->port_num; i++) { port = &dev->port[i]; -#ifdef DDB_USE_WORK - if (port->input[0] && port->input[0]->dma) - cancel_work_sync(&port->input[0]->dma->work); - if (port->input[1] && port->input[1]->dma) - cancel_work_sync(&port->input[1]->dma->work); - if (port->output && port->output->dma) - cancel_work_sync(&port->output->dma->work); -#else if (port->input[0] && port->input[0]->dma) tasklet_kill(&port->input[0]->dma->tasklet); if (port->input[1] && port->input[1]->dma) tasklet_kill(&port->input[1]->dma->tasklet); if (port->output && port->output->dma) tasklet_kill(&port->output->dma->tasklet); -#endif } } @@ -2790,9 +2870,6 @@ irqreturn_t ddb_irq_handler(int irq, void *dev_id) irq_handle_msg(dev, s); if (s & 0x0fffff00) { irq_handle_io(dev, s); -#ifdef DDB_TEST_THREADED - ret = IRQ_WAKE_THREAD; -#endif } } while ((s = ddbreadl(dev, INTERRUPT_STATUS))); @@ -2840,15 +2917,6 @@ irqreturn_t ddb_irq_handler_v2(int irq, void *dev_id) return ret; } -#ifdef DDB_TEST_THREADED -static irqreturn_t irq_thread(int irq, void *dev_id) -{ - /* struct ddb *dev = (struct ddb *) dev_id; */ - - return IRQ_HANDLED; -} -#endif - /****************************************************************************/ /****************************************************************************/ /****************************************************************************/ @@ -2988,7 +3056,7 @@ static int nsd_do_ioctl(struct file *file, unsigned int cmd, void *parg) static long nsd_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return dvb_usercopy(file, cmd, arg, nsd_do_ioctl); + return ddb_dvb_usercopy(file, cmd, arg, nsd_do_ioctl); } static const struct file_operations nsd_fops = { @@ -3160,69 +3228,6 @@ static u16 mdio_read(struct ddb *dev, u8 adr, u8 reg, u32 mdio_base) return ddbreadl(dev, MDIO_VAL_OFF + mdio_base); } -#define DDB_MAGIC 'd' - -struct ddb_flashio { - __u8 *write_buf; - __u32 write_len; - __u8 *read_buf; - __u32 read_len; - __u32 link; -}; - -struct ddb_gpio { - __u32 mask; - __u32 data; -}; - -struct ddb_id { - __u16 vendor; - __u16 device; - __u16 subvendor; - __u16 subdevice; - __u32 hw; - __u32 regmap; -}; - -struct ddb_reg { - __u32 reg; - __u32 val; -}; - -struct ddb_mem { - __u32 off; - __u8 *buf; - __u32 len; -}; - -struct ddb_mdio { - __u8 adr; - __u8 reg; - __u16 val; -}; - -struct ddb_i2c_msg { - __u8 bus; - __u8 adr; - __u8 *hdr; - __u32 hlen; - __u8 *msg; - __u32 mlen; -}; - -#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio) -#define IOCTL_DDB_GPIO_IN _IOWR(DDB_MAGIC, 0x01, struct ddb_gpio) -#define IOCTL_DDB_GPIO_OUT _IOWR(DDB_MAGIC, 0x02, struct ddb_gpio) -#define IOCTL_DDB_ID _IOR(DDB_MAGIC, 0x03, struct ddb_id) -#define IOCTL_DDB_READ_REG _IOWR(DDB_MAGIC, 0x04, struct ddb_reg) -#define IOCTL_DDB_WRITE_REG _IOW(DDB_MAGIC, 0x05, struct ddb_reg) -#define IOCTL_DDB_READ_MEM _IOWR(DDB_MAGIC, 0x06, struct ddb_mem) -#define IOCTL_DDB_WRITE_MEM _IOR(DDB_MAGIC, 0x07, struct ddb_mem) -#define IOCTL_DDB_READ_MDIO _IOWR(DDB_MAGIC, 0x08, struct ddb_mdio) -#define IOCTL_DDB_WRITE_MDIO _IOR(DDB_MAGIC, 0x09, struct ddb_mdio) -#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 DDB_NAME "ddbridge" static u32 ddb_num; @@ -3301,8 +3306,8 @@ static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) ddbid.device = dev->link[0].ids.device; ddbid.subvendor = dev->link[0].ids.subvendor; ddbid.subdevice = dev->link[0].ids.subdevice; - ddbid.hw = ddbreadl(dev, 0); - ddbid.regmap = ddbreadl(dev, 4); + ddbid.hw = dev->link[0].ids.hwid; + ddbid.regmap = dev->link[0].ids.regmapid; if (copy_to_user(parg, &ddbid, sizeof(ddbid))) return -EFAULT; break; @@ -3433,6 +3438,22 @@ static long ddb_ioctl(struct file *file, unsigned int cmd, unsigned long arg) return -EIO; break; } + case IOCTL_DDB_MCI_CMD: + { + struct ddb_mci_msg msg; + struct ddb_link *link; + int res; + + if (copy_from_user(&msg, parg, sizeof(msg))) + return -EFAULT; + if (msg.link > 3) + return -EFAULT; + link = &dev->link[msg.link]; + res = ddb_mci_cmd_link(link, &msg.cmd, &msg.res); + if (copy_to_user(parg, &msg, sizeof(msg))) + return -EFAULT; + return res; + } default: return -ENOTTY; } @@ -3693,19 +3714,23 @@ static ssize_t snr_show(struct device *device, struct ddb *dev = dev_get_drvdata(device); char snr[32]; int num = attr->attr.name[3] - 0x30; + struct ddb_port *port = &dev->port[num]; + struct i2c_adapter *i2c = &port->i2c->adap; - if (dev->port[num].type >= DDB_TUNER_XO2) { - if (i2c_read_regs(&dev->i2c[num].adap, 0x10, 0x10, snr, 16) < 0) + switch (port->type) { + case DDB_CI_EXTERNAL_XO2: + case DDB_TUNER_XO2 ... DDB_TUNER_DVBC2T2I_SONY: + if (i2c_read_regs(i2c, 0x10, 0x10, snr, 16) < 0) return sprintf(buf, "NO SNR\n"); snr[16] = 0; - } else { + break; + default: /* serial number at 0x100-0x11f */ - if (i2c_read_regs16(&dev->i2c[num].adap, - 0x57, 0x100, snr, 32) < 0) - if (i2c_read_regs16(&dev->i2c[num].adap, - 0x50, 0x100, snr, 32) < 0) + if (i2c_read_regs16(i2c, 0x57, 0x100, snr, 32) < 0) + if (i2c_read_regs16(i2c, 0x50, 0x100, snr, 32) < 0) return sprintf(buf, "NO SNR\n"); snr[31] = 0; /* in case it is not terminated on EEPROM */ + break; } return sprintf(buf, "%s\n", snr); } @@ -3716,15 +3741,17 @@ static ssize_t snr_store(struct device *device, struct device_attribute *attr, struct ddb *dev = dev_get_drvdata(device); int num = attr->attr.name[3] - 0x30; u8 snr[34] = { 0x01, 0x00 }; + struct ddb_port *port = &dev->port[num]; + struct i2c_adapter *i2c = &port->i2c->adap; return 0; /* NOE: remove completely? */ if (count > 31) return -EINVAL; - if (dev->port[num].type >= DDB_TUNER_XO2) + if (port->type >= DDB_TUNER_XO2) return -EINVAL; memcpy(snr + 2, buf, count); - i2c_write(&dev->i2c[num].adap, 0x57, snr, 34); - i2c_write(&dev->i2c[num].adap, 0x50, snr, 34); + i2c_write(i2c, 0x57, snr, 34); + i2c_write(i2c, 0x50, snr, 34); return count; } @@ -4414,6 +4441,50 @@ static int ddb_init_boards(struct ddb *dev) usleep_range(2000, 3000); } ddb_init_tempmon(link); + + if (info->regmap->mci) { + if (link->info->type == DDB_OCTOPUS_MCI || + ((link->info->type == DDB_MOD) && + (link->ids.regmapid & 0xfff0)) || + ((link->info->type == DDB_MOD) && + (link->ids.revision == 1))) + mci_init(link); + } + if (l) + continue; + if (dev->link[0].info->type == DDB_MOD && + dev->link[0].info->version == 2) { + u32 lic = ddbreadl(dev, 0x1c) & 7; + + if (dev->link[0].ids.revision == 1) + lic = ddbreadl(dev, 0x260) >> 24; + + switch (lic) { + case 0: + case 4: + dev->link[0].info = + get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0000); + break; + case 1: + case 8: + dev->link[0].info = + get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0003); + break; + case 2: + case 24: + dev->link[0].info = + get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0001); + break; + case 3: + case 16: + dev->link[0].info = + get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0002); + break; + default: + break; + } + dev_info(dev->dev, "Modulator channels: %u\n", dev->link[0].info->port_num); + } } return 0; } @@ -4440,8 +4511,10 @@ int ddb_init(struct ddb *dev) if (ddb_i2c_init(dev) < 0) goto fail; ddb_ports_init(dev); +#ifndef CONFIG_MACH_OCTONET if (dev->link[0].info->type == DDB_MOD) ddbridge_mod_init(dev); +#endif if (ddb_buffers_alloc(dev) < 0) { dev_info(dev->dev, "Could not allocate buffer memory\n"); @@ -4508,7 +4581,7 @@ int ddb_exit_ddbridge(int stage, int error) default: case 2: destroy_workqueue(ddb_wq); - /* fallthrough */ + fallthrough; case 1: ddb_class_destroy(); } diff --git a/ddbridge/ddbridge-hw.c b/ddbridge/ddbridge-hw.c index 083eff8..eeb95bc 100644 --- a/ddbridge/ddbridge-hw.c +++ b/ddbridge/ddbridge-hw.c @@ -124,6 +124,32 @@ static const struct ddb_regset octopus_i2c_buf = { /****************************************************************************/ +static const struct ddb_regset max_mci = { + .base = 0x500, + .num = 0x01, + .size = 0x04, +}; + +static const struct ddb_regset max_mci_buf = { + .base = 0x600, + .num = 0x01, + .size = 0x100, +}; + +static const struct ddb_regset sdr_mci = { + .base = 0x260, + .num = 0x01, + .size = 0x04, +}; + +static const struct ddb_regset sdr_mci_buf = { + .base = 0x300, + .num = 0x01, + .size = 0x100, +}; + +/****************************************************************************/ + static const struct ddb_regset octopro_input = { .base = 0x400, .num = 0x14, @@ -224,6 +250,25 @@ static const struct ddb_regmap octopus_map = { .output = &octopus_output, }; +static const struct ddb_regmap octopus_mci_map = { + .irq_version = 1, + .irq_base_i2c = 0, + .irq_base_idma = 8, + .irq_base_odma = 16, + .irq_base_mci = 0, + .i2c = &octopus_i2c, + .i2c_buf = &octopus_i2c_buf, + .idma = &octopus_idma, + .idma_buf = &octopus_idma_buf, + .odma = &octopus_odma, + .odma_buf = &octopus_odma_buf, + .input = &octopus_input, + .output = &octopus_output, + + .mci = &max_mci, + .mci_buf = &max_mci_buf, +}; + static const struct ddb_regmap octopro_map = { .irq_version = 2, .irq_base_i2c = 32, @@ -270,20 +315,28 @@ static const struct ddb_regmap octopus_mod_2_map = { .irq_version = 2, .irq_base_odma = 64, .irq_base_rate = 32, + .irq_base_mci = 10, .output = &octopus_output, .odma = &octopus_mod_2_odma, .odma_buf = &octopus_mod_2_odma_buf, .channel = &octopus_mod_2_channel, + + .mci = &sdr_mci, + .mci_buf = &sdr_mci_buf, }; static const struct ddb_regmap octopus_sdr_map = { .irq_version = 2, .irq_base_odma = 64, .irq_base_rate = 32, + .irq_base_mci = 10, .output = &octopus_sdr_output, .odma = &octopus_mod_2_odma, .odma_buf = &octopus_mod_2_odma_buf, .channel = &octopus_mod_2_channel, + + .mci = &sdr_mci, + .mci_buf = &sdr_mci_buf, }; static const struct ddb_regmap gtl_mini = { @@ -508,7 +561,7 @@ static const struct ddb_info ddb_mod_fsm_8 = { static const struct ddb_info ddb_mod_fsm_4 = { .type = DDB_MOD, - .name = "Digital Devices DVB-C modulator FSM-8", + .name = "Digital Devices DVB-C modulator FSM-4", .version = 2, .regmap = &octopus_mod_2_map, .port_num = 4, @@ -517,6 +570,17 @@ static const struct ddb_info ddb_mod_fsm_4 = { .lostlock_irq = 9, }; +static const struct ddb_info ddb_mod_fsm = { + .type = DDB_MOD, + .name = "Digital Devices DVB-C FSM", + .version = 2, + .regmap = &octopus_mod_2_map, + .port_num = 0, + .temp_num = 1, + .tempmon_irq = 8, + .lostlock_irq = 9, +}; + static const struct ddb_info ddb_sdr_atv = { .type = DDB_MOD, .name = "Digital Devices SDR ATV", @@ -537,12 +601,22 @@ static const struct ddb_info ddb_sdr_iq = { .tempmon_irq = 8, }; +static const struct ddb_info ddb_sdr_iq2 = { + .type = DDB_MOD, + .name = "Digital Devices SDR IQ2", + .version = 17, + .regmap = &octopus_sdr_map, + .port_num = 4, + .temp_num = 1, + .tempmon_irq = 8, +}; + static const struct ddb_info ddb_sdr_dvbt = { .type = DDB_MOD, .name = "Digital Devices DVBT", .version = 18, .regmap = &octopus_sdr_map, - .port_num = 16, + .port_num = 14, .temp_num = 1, .tempmon_irq = 8, }; @@ -568,7 +642,7 @@ static const struct ddb_info ddb_octopro = { static const struct ddb_info ddb_s2_48 = { .type = DDB_OCTOPUS_MAX, .name = "Digital Devices MAX S8 4/8", - .regmap = &octopus_map, + .regmap = &octopus_mci_map, .port_num = 4, .i2c_mask = 0x01, .board_control = 1, @@ -635,10 +709,12 @@ static const struct ddb_info ddb_c2t2i_8 = { .tempmon_irq = 24, }; +/****************************************************************************/ + static const struct ddb_info ddb_s2x_48 = { .type = DDB_OCTOPUS_MCI, .name = "Digital Devices MAX SX8", - .regmap = &octopus_map, + .regmap = &octopus_mci_map, .port_num = 4, .i2c_mask = 0x00, .tempmon_irq = 24, @@ -650,7 +726,7 @@ static const struct ddb_info ddb_s2x_48 = { static const struct ddb_info ddb_s2x_48_b = { .type = DDB_OCTOPUS_MCI, .name = "Digital Devices MAX SX8 Basic", - .regmap = &octopus_map, + .regmap = &octopus_mci_map, .port_num = 4, .i2c_mask = 0x00, .tempmon_irq = 24, @@ -662,7 +738,7 @@ static const struct ddb_info ddb_s2x_48_b = { static const struct ddb_info ddb_m4 = { .type = DDB_OCTOPUS_MCI, .name = "Digital Devices MAX M4", - .regmap = &octopus_map, + .regmap = &octopus_mci_map, .port_num = 2, .i2c_mask = 0x00, .tempmon_irq = 24, @@ -671,6 +747,8 @@ static const struct ddb_info ddb_m4 = { .temp_num = 1, }; +/****************************************************************************/ + static const struct ddb_info ddb_gtl_mini = { .type = DDB_OCTOPUS, .name = "Digital Devices Octopus GT Mini", @@ -806,6 +884,7 @@ static const struct ddb_device_id ddb_device_ids[] = { DDB_DEVID(0x0201, 0x0002, ddb_mod), DDB_DEVID(0x0201, 0x0004, ddb_mod_4), /* dummy entry ! */ DDB_DEVID(0x0203, 0x0001, ddb_mod), + DDB_DEVID(0x0210, 0x0004, ddb_mod_fsm), /* dummy entry ! */ DDB_DEVID(0x0210, 0x0000, ddb_mod_fsm_4), /* dummy entry ! */ DDB_DEVID(0x0210, 0x0001, ddb_mod_fsm_24), DDB_DEVID(0x0210, 0x0002, ddb_mod_fsm_16), @@ -813,6 +892,8 @@ static const struct ddb_device_id ddb_device_ids[] = { DDB_DEVID(0x0220, 0x0001, ddb_sdr_atv), DDB_DEVID(0x0221, 0x0001, ddb_sdr_iq), DDB_DEVID(0x0222, 0x0001, ddb_sdr_dvbt), + DDB_DEVID(0x0223, 0x0001, ddb_sdr_iq2), + DDB_DEVID(0xffff, 0xffff, ddb_sdr_iq2), /* testing on OctopusNet Pro */ DDB_DEVID(0x0320, 0xffff, ddb_octopro_hdin), diff --git a/ddbridge/ddbridge-io.c b/ddbridge/ddbridge-io.c index 8844a24..6df9a30 100644 --- a/ddbridge/ddbridge-io.c +++ b/ddbridge/ddbridge-io.c @@ -139,8 +139,8 @@ void gtlcpyfrom(struct ddb *dev, u8 *buf, u32 adr, long count) u32 a = p & 3; if (a) { - val = ddbreadl(dev, p) >> (8 * a); - while (p & 3 && count) { + val = ddbreadl(dev, p & ~3) >> (8 * a); + while ((p & 3) && count) { *buf = val & 0xff; val >>= 8; p++; @@ -177,7 +177,12 @@ void ddbcpyto(struct ddb *dev, u32 adr, void *src, long count) void ddbcpyfrom(struct ddb *dev, void *dst, u32 adr, long count) { + return gtlcpyfrom(dev, dst, adr, count); + /* The possible 64 bit read in memcpy_fromio produces errors + on some platforms, i.e. arm64 rpi4 if (unlikely(adr & 0xf0000000)) return gtlcpyfrom(dev, dst, adr, count); - return memcpy_fromio(dst, dev->regs + adr, count); + return memcpy_fromio(dst, dev->regs + adr, count); + */ + } diff --git a/ddbridge/ddbridge-ioctl.h b/ddbridge/ddbridge-ioctl.h new file mode 100644 index 0000000..332008e --- /dev/null +++ b/ddbridge/ddbridge-ioctl.h @@ -0,0 +1,74 @@ +#ifndef _DDBRIDGE_IOCTL_H_ +#define _DDBRIDGE_IOCTL_H_ + +#define DDB_MAGIC 'd' + +struct ddb_flashio { + __u8 *write_buf; + __u32 write_len; + __u8 *read_buf; + __u32 read_len; + __u32 link; +}; + +struct ddb_gpio { + __u32 mask; + __u32 data; +}; + +struct ddb_id { + __u16 vendor; + __u16 device; + __u16 subvendor; + __u16 subdevice; + __u32 hw; + __u32 regmap; +}; + +struct ddb_reg { + __u32 reg; + __u32 val; +}; + +struct ddb_mem { + __u32 off; + __u8 *buf; + __u32 len; +}; + +struct ddb_mdio { + __u8 adr; + __u8 reg; + __u16 val; +}; + +struct ddb_i2c_msg { + __u8 bus; + __u8 adr; + __u8 *hdr; + __u32 hlen; + __u8 *msg; + __u32 mlen; +}; + +struct ddb_mci_msg { + __u32 link; + struct mci_command cmd; + struct mci_result res; +}; + +#define IOCTL_DDB_FLASHIO _IOWR(DDB_MAGIC, 0x00, struct ddb_flashio) +#define IOCTL_DDB_GPIO_IN _IOWR(DDB_MAGIC, 0x01, struct ddb_gpio) +#define IOCTL_DDB_GPIO_OUT _IOWR(DDB_MAGIC, 0x02, struct ddb_gpio) +#define IOCTL_DDB_ID _IOR(DDB_MAGIC, 0x03, struct ddb_id) +#define IOCTL_DDB_READ_REG _IOWR(DDB_MAGIC, 0x04, struct ddb_reg) +#define IOCTL_DDB_WRITE_REG _IOW(DDB_MAGIC, 0x05, struct ddb_reg) +#define IOCTL_DDB_READ_MEM _IOWR(DDB_MAGIC, 0x06, struct ddb_mem) +#define IOCTL_DDB_WRITE_MEM _IOR(DDB_MAGIC, 0x07, struct ddb_mem) +#define IOCTL_DDB_READ_MDIO _IOWR(DDB_MAGIC, 0x08, struct ddb_mdio) +#define IOCTL_DDB_WRITE_MDIO _IOR(DDB_MAGIC, 0x09, struct ddb_mdio) +#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_MCI_CMD _IOWR(DDB_MAGIC, 0x0c, struct ddb_mci_msg) + +#endif diff --git a/ddbridge/ddbridge-m4.c b/ddbridge/ddbridge-m4.c index 661ede4..29a3a13 100644 --- a/ddbridge/ddbridge-m4.c +++ b/ddbridge/ddbridge-m4.c @@ -392,17 +392,23 @@ static int read_status(struct dvb_frontend *fe, enum fe_status *status) struct m4 *state = fe->demodulator_priv; struct mci_result res; + *status = 0x00; + if (!state->started) + return 0; stat = ddb_mci_get_status(&state->mci, &res); if (stat) return stat; - *status = 0x00; stat = ddb_mci_get_info(&state->mci); if (stat) return stat; ddb_mci_get_strength(fe); if (res.status == MCI_DEMOD_WAIT_SIGNAL) *status = 0x01; - if (res.status == MCI_DEMOD_LOCKED) { + else if (res.status == M4_DEMOD_WAIT_TS) + *status = 0x03; + else if (res.status == MCI_DEMOD_TIMEOUT) + *status = FE_TIMEDOUT; + else if (res.status == MCI_DEMOD_LOCKED) { *status = 0x1f; ddb_mci_get_snr(fe); } @@ -510,7 +516,7 @@ static int base_init(struct mci_base *mci_base) return 0; } -struct mci_cfg ddb_max_m4_cfg = { +static struct mci_cfg ddb_max_m4_cfg = { .type = 0, .fe_ops = &m4_ops, .base_size = sizeof(struct m4_base), @@ -518,3 +524,8 @@ struct mci_cfg ddb_max_m4_cfg = { .init = init, .base_init = base_init, }; + +struct dvb_frontend *ddb_m4_attach(struct ddb_input *input, int nr, int tuner) +{ + return ddb_mci_attach(input, &ddb_max_m4_cfg, nr, tuner); +} diff --git a/ddbridge/ddbridge-main.c b/ddbridge/ddbridge-main.c index 94da972..4ea279f 100644 --- a/ddbridge/ddbridge-main.c +++ b/ddbridge/ddbridge-main.c @@ -84,7 +84,7 @@ int pci_irq_vector(struct pci_dev *dev, unsigned int nr) /****************************************************************************/ /****************************************************************************/ -static void __devexit ddb_irq_disable(struct ddb *dev) +static void ddb_irq_disable(struct ddb *dev) { if (dev->link[0].info->regmap->irq_version == 2) { ddbwritel(dev, 0x00000000, INTERRUPT_V2_CONTROL); @@ -114,7 +114,7 @@ static void __devexit ddb_msi_exit(struct ddb *dev) #endif } -static void __devexit ddb_irq_exit(struct ddb *dev) +static void ddb_irq_exit(struct ddb *dev) { ddb_irq_disable(dev); if (dev->msi == 2) @@ -139,6 +139,7 @@ static void __devexit ddb_remove(struct pci_dev *pdev) ddb_buffers_free(dev); ddb_unmap(dev); + pci_clear_master(pdev); pci_set_drvdata(pdev, NULL); pci_disable_device(pdev); } @@ -254,17 +255,9 @@ static int __devinit ddb_irq_init(struct ddb *dev) return stat; } } else { -#ifdef DDB_TEST_THREADED - stat = request_threaded_irq(pci_irq_vector(dev->pdev, 0), - dev->pdev->irq, ddb_irq_handler, - irq_thread, - irq_flag, - "ddbridge", (void *)dev); -#else stat = request_irq(pci_irq_vector(dev->pdev, 0), ddb_irq_handler, irq_flag, "ddbridge", (void *)dev); -#endif if (stat < 0) return stat; } @@ -290,9 +283,17 @@ static int __devinit ddb_probe(struct pci_dev *pdev, pci_set_master(pdev); - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) - if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) - return -ENODEV; +#if (KERNEL_VERSION(5, 18, 0) <= LINUX_VERSION_CODE) + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64))) + if (dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32))) +#else + if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(64))) { + pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(64)); + } else if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) { + pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + } else +#endif + return -ENODEV; dev = vzalloc(sizeof(*dev)); if (!dev) @@ -309,11 +310,11 @@ static int __devinit ddb_probe(struct pci_dev *pdev, dev->link[0].ids.subvendor = id->subvendor; dev->link[0].ids.subdevice = pdev->subsystem_device; dev->link[0].ids.devid = (id->device << 16) | id->vendor; + dev->link[0].ids.revision = pdev->revision; dev->link[0].dev = dev; dev->link[0].info = get_ddb_info(id->vendor, id->device, id->subvendor, pdev->subsystem_device); - dev_info(dev->dev, "device name: %s\n", dev->link[0].info->name); dev->regs_len = pci_resource_len(dev->pdev, 0); dev->regs = ioremap(pci_resource_start(dev->pdev, 0), @@ -333,14 +334,12 @@ static int __devinit ddb_probe(struct pci_dev *pdev, dev->link[0].ids.hwid = ddbreadl(dev, 0); dev->link[0].ids.regmapid = ddbreadl(dev, 4); - dev_info(dev->dev, "HW %08x REGMAP %08x\n", - dev->link[0].ids.hwid, dev->link[0].ids.regmapid); if ((dev->link[0].ids.hwid & 0xffffff) < dev->link[0].info->hw_min) { u32 min = dev->link[0].info->hw_min; dev_err(dev->dev, "Update firmware to at least version %u.%u to ensure full functionality!\n", - (min & 0xff0000) >> 16, min & 0xffff); + (min & 0xff0000) >> 16, min & 0xffff); } if (dev->link[0].info->ns_num) { @@ -351,33 +350,27 @@ static int __devinit ddb_probe(struct pci_dev *pdev, if (dev->link[0].info->type != DDB_MOD) ddbwritel(dev, 0, DMA_BASE_WRITE); - if (dev->link[0].info->type == DDB_MOD - && dev->link[0].info->version <= 1) { + if (dev->link[0].info->type == DDB_MOD && + dev->link[0].info->version <= 1) { if (ddbreadl(dev, 0x1c) == 4) dev->link[0].info = get_ddb_info(0xdd01, 0x0201, 0xdd01, 0x0004); } - if (dev->link[0].info->type == DDB_MOD - && dev->link[0].info->version == 2) { - u32 lic = ddbreadl(dev, 0x1c) & 7; - switch (lic) { - case 0: - dev->link[0].info = - get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0000); - break; - case 1: - dev->link[0].info = - get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0003); - break; - case 3: - dev->link[0].info = - get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0002); - break; - default: - break; - } + if (dev->link[0].info->type == DDB_MOD && + dev->link[0].info->version == 2) { + if (dev->link[0].ids.revision == 1) + dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0004); + else if ((ddbreadl(dev, 0x1c) & 7) != 7) + dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0004); } + + dev_info(dev->dev, "%s\n", dev->link[0].info->name); + dev_info(dev->dev, "HW %08x REGMAP %08x FW %u.%u\n", + dev->link[0].ids.hwid, dev->link[0].ids.regmapid, + (dev->link[0].ids.hwid & 0xff0000) >> 16, + dev->link[0].ids.hwid & 0xffff); + stat = ddb_irq_init(dev); if (stat < 0) goto fail0; @@ -402,6 +395,12 @@ fail: /****************************************************************************/ /****************************************************************************/ +#ifndef PCI_DEVICE_SUB +#define PCI_DEVICE_SUB(vend, dev, subvend, subdev) \ + .vendor = (vend), .device = (dev), \ + .subvendor = (subvend), .subdevice = (subdev) +#endif + #define DDB_DEVICE_ANY(_device) \ { PCI_DEVICE_SUB(0xdd01, _device, 0xdd01, PCI_ANY_ID) } @@ -425,6 +424,7 @@ static const struct pci_device_id ddb_id_table[] __devinitconst = { DDB_DEVICE_ANY(0x0220), DDB_DEVICE_ANY(0x0221), DDB_DEVICE_ANY(0x0222), + DDB_DEVICE_ANY(0x0223), DDB_DEVICE_ANY(0x0320), DDB_DEVICE_ANY(0x0321), DDB_DEVICE_ANY(0x0322), @@ -435,7 +435,6 @@ static const struct pci_device_id ddb_id_table[] __devinitconst = { }; MODULE_DEVICE_TABLE(pci, ddb_id_table); - static pci_ers_result_t ddb_pci_slot_reset(struct pci_dev *dev) { pr_info("pci_slot_reset\n"); @@ -475,7 +474,6 @@ static const struct pci_error_handlers ddb_error = { .resume = ddb_pci_resume, }; - static struct pci_driver ddb_pci_driver = { .name = "ddbridge", .id_table = ddb_id_table, diff --git a/ddbridge/ddbridge-max.c b/ddbridge/ddbridge-max.c index 8816afe..b79a479 100644 --- a/ddbridge/ddbridge-max.c +++ b/ddbridge/ddbridge-max.c @@ -40,6 +40,10 @@ static int old_quattro; module_param(old_quattro, int, 0444); MODULE_PARM_DESC(old_quattro, "old quattro LNB input order "); +static int no_voltage; +module_param(no_voltage, int, 0444); +MODULE_PARM_DESC(no_voltage, "Do not enable voltage on LNBH (will also disable 22KHz tone)."); + /* MAX LNB interface related functions */ static int lnb_command(struct ddb *dev, u32 link, u32 lnb, u32 cmd) @@ -61,7 +65,7 @@ static int lnb_command(struct ddb *dev, u32 link, u32 lnb, u32 cmd) return 0; } -static int max_set_input_unlocked(struct dvb_frontend *fe, int in); +static int max_set_input(struct dvb_frontend *fe, int in); static int max_emulate_switch(struct dvb_frontend *fe, u8 *cmd, u32 len) @@ -75,7 +79,7 @@ static int max_emulate_switch(struct dvb_frontend *fe, return -1; input = cmd[3] & 3; - max_set_input_unlocked(fe, input); + max_set_input(fe, input); return 0; } @@ -94,7 +98,8 @@ static int max_send_master_cmd(struct dvb_frontend *fe, return 0; if (fmode == 4) - max_emulate_switch(fe, cmd->msg, cmd->msg_len); + if (!max_emulate_switch(fe, cmd->msg, cmd->msg_len)) + return 0; if (dvb->diseqc_send_master_cmd) dvb->diseqc_send_master_cmd(fe, cmd); @@ -164,6 +169,8 @@ static int lnb_set_voltage(struct ddb *dev, u32 link, u32 input, { int s = 0; + if (no_voltage) + voltage = SEC_VOLTAGE_OFF; if (dev->link[link].lnb.oldvoltage[input] == voltage) return 0; switch (voltage) { @@ -465,7 +472,8 @@ int ddb_fe_attach_mxl5xx(struct ddb_input *input) tuner = demod & 3; if (fmode >= 3) tuner = 0; - dvb->fe = dvb_attach(mxl5xx_attach, i2c, &cfg, demod, tuner); + dvb->fe = dvb_attach(mxl5xx_attach, i2c, &cfg, + demod, tuner, &dvb->set_input); if (!dvb->fe) { dev_err(dev->dev, "No MXL5XX found!\n"); return -ENODEV; @@ -483,13 +491,17 @@ int ddb_fe_attach_mxl5xx(struct ddb_input *input) dvb->fe->ops.diseqc_send_master_cmd = max_send_master_cmd; dvb->fe->ops.diseqc_send_burst = max_send_burst; dvb->fe->sec_priv = input; - dvb->set_input = dvb->fe->ops.set_input; +#ifndef KERNEL_DVB_CORE dvb->fe->ops.set_input = max_set_input; +#endif dvb->input = tuner; return 0; } /* MAX MCI related functions */ +struct dvb_frontend *ddb_sx8_attach(struct ddb_input *input, int nr, int tuner, + int (**fn_set_input)(struct dvb_frontend *fe, int input)); +struct dvb_frontend *ddb_m4_attach(struct ddb_input *input, int nr, int tuner); int ddb_fe_attach_mci(struct ddb_input *input, u32 type) { @@ -498,25 +510,23 @@ int ddb_fe_attach_mci(struct ddb_input *input, u32 type) struct ddb_port *port = input->port; struct ddb_link *link = &dev->link[port->lnr]; int demod, tuner; - struct mci_cfg cfg; int fm = fmode; demod = input->nr; tuner = demod & 3; switch (type) { case DDB_TUNER_MCI_SX8: - cfg = ddb_max_sx8_cfg; if (fm >= 3) tuner = 0; + dvb->fe = ddb_sx8_attach(input, demod, tuner, &dvb->set_input); break; case DDB_TUNER_MCI_M4: fm = 0; - cfg = ddb_max_m4_cfg; + dvb->fe = ddb_m4_attach(input, demod, tuner); break; default: return -EINVAL; } - dvb->fe = ddb_mci_attach(input, &cfg, demod, tuner); if (!dvb->fe) { dev_err(dev->dev, "No MCI card found!\n"); return -ENODEV; @@ -538,8 +548,9 @@ int ddb_fe_attach_mci(struct ddb_input *input, u32 type) case DDB_TUNER_MCI_M4: break; default: - dvb->set_input = dvb->fe->ops.set_input; +#ifndef KERNEL_DVB_CORE dvb->fe->ops.set_input = max_set_input; +#endif break; } dvb->input = tuner; diff --git a/ddbridge/ddbridge-mci.c b/ddbridge/ddbridge-mci.c index b617064..0d093aa 100644 --- a/ddbridge/ddbridge-mci.c +++ b/ddbridge/ddbridge-mci.c @@ -28,151 +28,192 @@ static LIST_HEAD(mci_list); -static int mci_reset(struct mci *state) +static int mci_reset(struct ddb_link *link) { - struct ddb_link *link = state->base->link; + const struct ddb_regmap *regmap = link->info->regmap; + u32 control; u32 status = 0; u32 timeout = 40; + union { + u32 u[4]; + char s[16]; + } version; + u32 vaddr; + + if (!regmap || !regmap->mci) + return -EINVAL; + control = regmap->mci->base; + vaddr = regmap->mci_buf->base + 0xf0; - ddblwritel(link, MCI_CONTROL_RESET, MCI_CONTROL); - ddblwritel(link, 0, MCI_CONTROL + 4); /* 1= no internal init */ - msleep(300); - ddblwritel(link, 0, MCI_CONTROL); - + if ((link->info->type == DDB_OCTOPUS_MCI) && + (ddblreadl(link, control) & MCI_CONTROL_START_COMMAND)) { + ddblwritel(link, MCI_CONTROL_RESET, control); + ddblwritel(link, 0, control + 4); /* 1= no internal init */ + msleep(300); + } + ddblwritel(link, 0, control); while (1) { - status = ddblreadl(link, MCI_CONTROL); + status = ddblreadl(link, control); if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY) break; if (--timeout == 0) break; msleep(50); } - if ((status & MCI_CONTROL_READY) == 0) + dev_info(link->dev->dev, "MCI control port @ %08x\n", control); + + if ((status & MCI_CONTROL_READY) == 0) { + dev_err(link->dev->dev, "MCI init failed!\n"); return -1; - if (link->ids.device == 0x0009 || link->ids.device == 0x000b) - ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG); + } + version.u[0] = ddblreadl(link, vaddr); + version.u[1] = ddblreadl(link, vaddr + 4); + version.u[2] = ddblreadl(link, vaddr + 8); + version.u[3] = ddblreadl(link, vaddr + 12); + dev_info(link->dev->dev, "MCI port OK, init time %u msecs\n", (40 - timeout) * 50); + dev_info(link->dev->dev, "MCI firmware version %s.%d\n", version.s, version.s[15]); return 0; } -int ddb_mci_config(struct mci *state, u32 config) -{ - struct ddb_link *link = state->base->link; - - if (link->ids.device != 0x0009 && link->ids.device != 0x000b) - return -EINVAL; - ddblwritel(link, config, SX8_TSCONFIG); - return 0; -} - - -static int ddb_mci_cmd_raw_unlocked(struct mci *state, +static int ddb_mci_cmd_raw_unlocked(struct ddb_link *link, u32 *cmd, u32 cmd_len, u32 *res, u32 res_len) { - struct ddb_link *link = state->base->link; + const struct ddb_regmap *regmap = link->info->regmap; + u32 control, command, result; u32 i, val; unsigned long stat; - val = ddblreadl(link, MCI_CONTROL); + if (!regmap || ! regmap->mci) + return -EINVAL; + control = regmap->mci->base; + command = regmap->mci_buf->base; + result = command + MCI_COMMAND_SIZE; + val = ddblreadl(link, control); if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND)) return -EIO; if (cmd && cmd_len) for (i = 0; i < cmd_len; i++) - ddblwritel(link, cmd[i], MCI_COMMAND + i * 4); - val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT); - ddblwritel(link, val, MCI_CONTROL); + ddblwritel(link, cmd[i], command + i * 4); + val |= (MCI_CONTROL_START_COMMAND | + MCI_CONTROL_ENABLE_DONE_INTERRUPT); + ddblwritel(link, val, control); - stat = wait_for_completion_timeout(&state->base->completion, HZ); + stat = wait_for_completion_timeout(&link->mci_completion, HZ); if (stat == 0) { u32 istat = ddblreadl(link, INTERRUPT_STATUS); - dev_err(state->base->link->dev->dev, "MCI timeout\n"); - val = ddblreadl(link, MCI_CONTROL); + dev_err(link->dev->dev, "MCI timeout\n"); + val = ddblreadl(link, control); if (val == 0xffffffff) { - dev_err(state->base->link->dev->dev, + dev_err(link->dev->dev, "Lost PCIe link!\n"); return -EIO; } else { - dev_err(state->base->link->dev->dev, - "DDBridge IRS %08x link %u\n", istat, link->nr); + dev_err(link->dev->dev, + "DDBridge IRS %08x link %u\n", + istat, link->nr); if (istat & 1) ddblwritel(link, istat, INTERRUPT_ACK); if (link->nr) - ddbwritel(link->dev, 0xffffff, INTERRUPT_ACK); + ddbwritel(link->dev, + 0xffffff, INTERRUPT_ACK); } } + //print_hex_dump(KERN_INFO, "MCI", DUMP_PREFIX_OFFSET, 16, 1, cmd, cmd_len, false); if (res && res_len) for (i = 0; i < res_len; i++) - res[i] = ddblreadl(link, MCI_RESULT + i * 4); + res[i] = ddblreadl(link, result + i * 4); return 0; } -int ddb_mci_cmd_unlocked(struct mci *state, - struct mci_command *command, - struct mci_result *result) +int ddb_mci_cmd_link(struct ddb_link *link, + struct mci_command *command, + struct mci_result *result) { - u32 *cmd = (u32 *) command; - u32 *res = (u32 *) result; - - return ddb_mci_cmd_raw_unlocked(state, cmd, sizeof(*command)/sizeof(u32), - res, sizeof(*result)/sizeof(u32)); -} - -int ddb_mci_cmd(struct mci *state, - struct mci_command *command, - struct mci_result *result) -{ - int stat; struct mci_result res; + int stat; + if (!link->mci_ok) + return -EFAULT; if (!result) result = &res; - mutex_lock(&state->base->mci_lock); - stat = ddb_mci_cmd_raw_unlocked(state, - (u32 *)command, sizeof(*command)/sizeof(u32), - (u32 *)result, sizeof(*result)/sizeof(u32)); - mutex_unlock(&state->base->mci_lock); + mutex_lock(&link->mci_lock); + stat = ddb_mci_cmd_raw_unlocked(link, + (u32 *)command, + sizeof(*command)/sizeof(u32), + (u32 *)result, + sizeof(*result)/sizeof(u32)); + mutex_unlock(&link->mci_lock); if (command && result && (result->status & 0x80)) - dev_warn(state->base->link->dev->dev, + dev_warn(link->dev->dev, "mci_command 0x%02x, error=0x%02x\n", command->command, result->status); return stat; } +static void mci_handler(void *priv) +{ + struct ddb_link *link = (struct ddb_link *) priv; + + complete(&link->mci_completion); +} + +int mci_init(struct ddb_link *link) +{ + int result; + + mutex_init(&link->mci_lock); + init_completion(&link->mci_completion); + result = mci_reset(link); + if (result < 0) + return result; + if (link->ids.device == 0x0009 || link->ids.device == 0x000b) + ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG); + + ddb_irq_set(link->dev, link->nr, + link->info->regmap->irq_base_mci, + mci_handler, link); + link->mci_ok = 1; + return result; +} + +int mci_cmd_val(struct ddb_link *link, uint32_t cmd, uint32_t val) +{ + struct mci_result result; + struct mci_command command; + + command.command_word = cmd; + command.params[0] = val; + return ddb_mci_cmd_link(link, &command, &result); +} + +/****************************************************************************/ +/****************************************************************************/ + +int ddb_mci_cmd(struct mci *state, + struct mci_command *command, + struct mci_result *result) +{ + return ddb_mci_cmd_link(state->base->link, command, result); +} + + int ddb_mci_cmd_raw(struct mci *state, struct mci_command *command, u32 command_len, struct mci_result *result, u32 result_len) { + struct ddb_link *link = state->base->link; int stat; - mutex_lock(&state->base->mci_lock); - stat = ddb_mci_cmd_raw_unlocked(state, + mutex_lock(&link->mci_lock); + stat = ddb_mci_cmd_raw_unlocked(link, (u32 *)command, command_len, (u32 *)result, result_len); - mutex_unlock(&state->base->mci_lock); + mutex_unlock(&link->mci_lock); return stat; } -#if 0 -static int ddb_mci_get_iq(struct mci *mci, u32 demod, s16 *i, s16 *q) -{ - int stat; - struct mci_command cmd; - struct mci_result res; - - memset(&cmd, 0, sizeof(cmd)); - memset(&res, 0, sizeof(res)); - cmd.command = MCI_CMD_GET_IQSYMBOL; - cmd.demod = demod; - stat = ddb_mci_cmd(mci, &cmd, &res); - if (!stat) { - *i = res.iq_symbol.i; - *q = res.iq_symbol.q; - } - return stat; -} -#endif - int ddb_mci_get_status(struct mci *mci, struct mci_result *res) { struct mci_command cmd; @@ -189,7 +230,8 @@ int ddb_mci_get_snr(struct dvb_frontend *fe) p->cnr.len = 1; p->cnr.stat[0].scale = FE_SCALE_DECIBEL; - p->cnr.stat[0].svalue = (s64) mci->signal_info.dvbs2_signal_info.signal_to_noise * 10; + p->cnr.stat[0].svalue = + (s64) mci->signal_info.dvbs2_signal_info.signal_to_noise * 10; return 0; } @@ -245,7 +287,7 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) }; const enum fe_code_rate dvbs_fec_lut[8] = { FEC_1_2, FEC_2_3, FEC_3_4, FEC_5_6, - FEC_NONE, FEC_7_8, FEC_NONE, FEC_NONE, + FEC_7_8, FEC_7_8, FEC_NONE, FEC_NONE, }; const enum fe_rolloff ro_lut[8] = { ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_10, @@ -254,6 +296,8 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) p->frequency = mci->signal_info.dvbs2_signal_info.frequency; + p->symbol_rate = + mci->signal_info.dvbs2_signal_info.symbol_rate; switch (p->delivery_system) { default: case SYS_DVBS: @@ -266,6 +310,8 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) p->delivery_system = (mci->signal_info.dvbs2_signal_info.standard == 2) ? SYS_DVBS2 : SYS_DVBS; + p->inversion = (mci->signal_info.dvbs2_signal_info.roll_off & 0x80) ? + INVERSION_ON : INVERSION_OFF; if (mci->signal_info.dvbs2_signal_info.standard == 2) { u32 modcod; @@ -296,6 +342,8 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) break; } case SYS_DVBC_ANNEX_A: + p->modulation = + mci->signal_info.dvbc_signal_info.constellation + 1; break; case SYS_DVBT: break; @@ -306,6 +354,8 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) case SYS_ISDBT: break; } + /* post is correct, we cannot provide both pre and post at the same time */ + /* set pre and post the same for now */ p->pre_bit_error.len = 1; p->pre_bit_error.stat[0].scale = FE_SCALE_COUNTER; p->pre_bit_error.stat[0].uvalue = @@ -316,6 +366,16 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) p->pre_bit_count.stat[0].uvalue = mci->signal_info.dvbs2_signal_info.ber_denominator; + p->post_bit_error.len = 1; + p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER; + p->post_bit_error.stat[0].uvalue = + mci->signal_info.dvbs2_signal_info.ber_numerator; + + p->post_bit_count.len = 1; + p->post_bit_count.stat[0].scale = FE_SCALE_COUNTER; + p->post_bit_count.stat[0].uvalue = + mci->signal_info.dvbs2_signal_info.ber_denominator; + p->block_error.len = 1; p->block_error.stat[0].scale = FE_SCALE_COUNTER; p->block_error.stat[0].uvalue = @@ -329,17 +389,10 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) p->strength.len = 1; p->strength.stat[0].scale = FE_SCALE_DECIBEL; - p->strength.stat[0].svalue = + p->strength.stat[0].svalue = (s64) mci->signal_info.dvbs2_signal_info.channel_power * 10; } -static void mci_handler(void *priv) -{ - struct mci_base *base = (struct mci_base *)priv; - - complete(&base->completion); -} - static struct mci_base *match_base(void *key) { struct mci_base *p; @@ -350,13 +403,8 @@ static struct mci_base *match_base(void *key) return NULL; } -static int probe(struct mci *state) -{ - mci_reset(state); - return 0; -} - -struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg, int nr, int tuner) +struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, + struct mci_cfg *cfg, int nr, int tuner) { struct ddb_port *port = input->port; struct ddb *dev = port->dev; @@ -380,12 +428,11 @@ struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg base->key = key; base->count = 1; base->link = link; - mutex_init(&base->mci_lock); + link->mci_base = base; mutex_init(&base->tuner_lock); - ddb_irq_set(dev, link->nr, 0, mci_handler, base); - init_completion(&base->completion); state->base = base; - if (probe(state) < 0) { + + if (!link->mci_ok) { kfree(base); goto fail; } diff --git a/ddbridge/ddbridge-mci.h b/ddbridge/ddbridge-mci.h index 2fe37bc..c604cf9 100644 --- a/ddbridge/ddbridge-mci.h +++ b/ddbridge/ddbridge-mci.h @@ -39,11 +39,6 @@ #define MIC_INTERFACE_OUT (0x0680) #define MIC_INTERFACE_VER (0x06F0) - -#define MCI_CONTROL (0x500) -#define MCI_COMMAND (0x600) -#define MCI_RESULT (0x680) - #define MCI_COMMAND_SIZE (0x80) #define MCI_RESULT_SIZE (0x80) @@ -106,6 +101,8 @@ #define MCI_STATUS_OK (0x00) #define MCI_STATUS_UNSUPPORTED (0x80) +#define MCI_STATUS_BUSY (0xFA) +#define MCI_STATUS_HARDWARE_ERROR (0xFB) #define MCI_STATUS_INVALID_PARAMETER (0xFC) #define MCI_STATUS_RETRY (0xFD) #define MCI_STATUS_NOT_READY (0xFE) @@ -137,6 +134,7 @@ #define MCI_BANDWIDTH_7MHZ (7) #define MCI_BANDWIDTH_8MHZ (8) +#define SX8_CMD_GETBIST (0x0F) #define SX8_CMD_INPUT_ENABLE (0x40) #define SX8_CMD_INPUT_DISABLE (0x41) #define SX8_CMD_START_IQ (0x42) @@ -159,7 +157,7 @@ #define M4_L1INFO_SEL_PLPINFO (2) #define M4_L1INFO_SEL_PLPINFO_C (3) #define M4_L1INFO_SEL_SETID (0x80) - + #define MCI_BANDWIDTH_EXTENSION (0x80) // currently used only for J83B in Japan #define M4_MODE_DVBSX (2) @@ -171,13 +169,13 @@ #define M4_MODE_ISDBT (8) #define M4_MODE_ISDBC (9) #define M4_MODE_ISDBS (10) - + #define M4_DVBC_CONSTELLATION_16QAM (0) #define M4_DVBC_CONSTELLATION_32QAM (1) #define M4_DVBC_CONSTELLATION_64QAM (2) // also valid for J83B and ISDB-C #define M4_DVBC_CONSTELLATION_128QAM (3) #define M4_DVBC_CONSTELLATION_256QAM (4) // also valid for J83B and ISDB-C - + #define M4_SIGNALINFO_FLAG_CHANGE (0x01) #define M4_SIGNALINFO_FLAG_EWS (0x02) @@ -186,10 +184,132 @@ #define SX8_ROLLOFF_20 2 #define SX8_ROLLOFF_15 5 #define SX8_ROLLOFF_10 3 -#define SX8_ROLLOFF_05 4 +#define SX8_ROLLOFF_05 4 #define MCI_SUCCESS(status) ((status & MCI_STATUS_UNSUPPORTED) == 0) +/********************************************************/ + +#define MOD_SETUP_CHANNELS (0x60) +#define MOD_SETUP_OUTPUT (0x61) +#define MOD_SETUP_STREAM (0x62) +#define MOD_SET_STREAM_CHANNEL (0x63) + +#define MOD_SETUP_FLAG_FIRST (0x01) +#define MOD_SETUP_FLAG_LAST (0x02) +#define MOD_SETUP_FLAG_VALID (0x80) + +#define MOD_STANDARD_GENERIC (0x00) +#define MOD_STANDARD_DVBT_8 (0x01) +#define MOD_STANDARD_DVBT_7 (0x02) +#define MOD_STANDARD_DVBT_6 (0x03) +#define MOD_STANDARD_DVBT_5 (0x04) + +#define MOD_STANDARD_DVBC_8 (0x08) +#define MOD_STANDARD_DVBC_7 (0x09) +#define MOD_STANDARD_DVBC_6 (0x0A) + +#define MOD_STANDARD_J83A_8 (MOD_STANDARD_DVBC_8) +#define MOD_STANDARD_J83A_7 (MOD_STANDARD_DVBC_7) +#define MOD_STANDARD_J83A_6 (MOD_STANDARD_DVBC_6) + +#define MOD_STANDARD_J83B_QAM64 (0x0B) +#define MOD_STANDARD_J83B_QAM256 (0x0C) + +#define MOD_STANDARD_ISDBC_QAM64 (0x0D) +#define MOD_STANDARD_ISDBC_QAM256 (0x0E) + +#define MOD_STANDARD_J83C_QAM64 (MOD_STANDARD_ISDBC_QAM64 ) +#define MOD_STANDARD_J83C_QAM256 (MOD_STANDARD_ISDBC_QAM256) + +#define MOD_CONNECTOR_OFF (0x00) +#define MOD_CONNECTOR_F (0x01) +#define MOD_CONNECTOR_SMA (0x02) + +#define MOD_UNIT_DBUV (0x00) +#define MOD_UNIT_DBM (0x01) + +#define MOD_FORMAT_DEFAULT (0x00) +#define MOD_FORMAT_IQ16 (0x01) +#define MOD_FORMAT_IQ8 (0x02) +#define MOD_FORMAT_IDX8 (0x03) +#define MOD_FORMAT_TS (0x04) + +#define MOD_DVBT_FFT_8K (0x01) +#define MOD_DVBT_GI_1_32 (0x00) +#define MOD_DVBT_GI_1_16 (0x01) +#define MOD_DVBT_GI_1_8 (0x02) +#define MOD_DVBT_GI_1_4 (0x03) + +#define MOD_DVBT_PR_1_2 (0x00) +#define MOD_DVBT_PR_2_3 (0x01) +#define MOD_DVBT_PR_3_4 (0x02) +#define MOD_DVBT_PR_5_6 (0x03) +#define MOD_DVBT_PR_7_8 (0x04) + +#define MOD_DVBT_QPSK (0x00) +#define MOD_DVBT_16QAM (0x01) +#define MOD_DVBT_64QAM (0x02) + +#define MOD_QAM_DVBC_16 (0x00) +#define MOD_QAM_DVBC_32 (0x01) +#define MOD_QAM_DVBC_64 (0x02) +#define MOD_QAM_DVBC_128 (0x03) +#define MOD_QAM_DVBC_256 (0x04) + +#define MOD_QAM_J83B_64 (0x05) +#define MOD_QAM_J83B_256 (0x06) + +#define MOD_QAM_GENERIC (0x07) + +#define MOD_QAM_ISDBC_64 (0x08) +#define MOD_QAM_ISDBC_256 (0x09) + +#define CMD_GET_SERIALNUMBER (0xF0) +#define CMD_EXPORT_LICENSE (0xF0) + +struct mod_setup_channels { + u8 flags; + u8 standard; + u8 num_channels; + u8 rsvd; + u32 frequency; + u32 offset; /* used only when Standard == 0 */ + u32 bandwidth; /* used only when Standard == 0 */ +}; + +struct mod_ofdm_parameter { + u8 fft_size; /* 0 = 2K, 1 = 8K (2K not yet supported) */ + u8 guard_interval; /* 0 = 1/32, 1 = 1/16, 2 = 1/8, 3 = 1/4 (DVB-T Encoding) */ + u8 puncture_rate; /* 0 = 1/2, 1 = 2/3, 2 = 3/4, 3 = 5/6, 4 = 7/8 (DVB-T Encoding) */ + u8 constellation; /* MOD_DVBT_QPSK, MOD_DVBT_16QAM, MOD_DVBT_64QAM */ + u8 rsvd2[2]; /* Reserved for DVB-T hierarchical */ + u16 cell_identifier; +}; + +struct mod_qam_parameter { + u8 modulation; + u8 rolloff; /* Legal values: 12,13,15,18 */ +}; + +struct mod_setup_stream { + u8 standard; + u8 stream_format; + u8 rsvd1[2]; + u32 symbol_rate; /* only used when Standard doesn't define a fixed symbol rate */ + union { + struct mod_ofdm_parameter ofdm; + struct mod_qam_parameter qam; + }; +}; + +struct mod_setup_output { + u8 connector; /* 0 = OFF, 1 = F, 2 = SMA */ + u8 num_channels; /* max active channels, determines max power for each channel. */ + u8 unit; /* 0 = dBµV, 1 = dBm, */ + u8 rsvd; + s16 channel_power; +}; /********************************************************/ @@ -202,9 +322,16 @@ struct mci_command { u8 demod; u8 output; }; + struct { + u8 mod_command; + u8 mod_channel; + u8 mod_stream; + u8 mod_rsvd1; + }; }; union { u32 params[31]; + u8 params8[31*4]; struct { u8 flags; /* Bit 0: DVB-S Enabled, 1: DVB-S2 Enabled, 5: ChannelBonding, 6: FrequencyRange, 7: InputStreamID */ @@ -220,7 +347,7 @@ struct mci_command { u32 scrambling_sequence_index; u32 frequency_range; u8 channel_bonding_config; /* Bit 7: IsSlave, Bit 5..4: MasterDemod, - bit 0: Num channels - 2. + bit 0: Num channels - 2. (must be set on all channels to same value) */ } dvbs2_search; @@ -241,7 +368,7 @@ struct mci_command { u8 retry; u32 frequency; } dvbc_search; - + struct { u8 flags; /* Bit 0: LP Stream */ u8 bandwidth; @@ -249,7 +376,7 @@ struct mci_command { u8 retry; u32 frequency; } dvbt_search; - + struct { u8 flags; /* Bit 0: T2 Lite Profile, 7: PLP, */ u8 bandwidth; @@ -260,7 +387,7 @@ struct mci_command { u8 plp; u8 rsvd2[3]; } dvbt2_search; - + struct { u8 flags; u8 bandwidth; @@ -272,15 +399,15 @@ struct mci_command { u8 data_slice; u8 rsvd2[2]; } dvbc2_search; - + struct { - u8 flags; + u8 flags; u8 bandwidth; u8 rsvd1; u8 retry; u32 frequency; } isdbt_search; - + struct { u8 flags; /* Bit 0: 0 = TSID is Transport Stream ID, 1 = TSID is relative stream number */ /* Bit 2..1: 0 = force single, 1 = force multi, 2 = auto detect */ @@ -292,7 +419,7 @@ struct mci_command { u16 onid; u16 tsid; } isdbc_search; - + struct { u8 flags; u8 bandwidth; @@ -302,7 +429,7 @@ struct mci_command { } j83b_search; struct { - u8 flags; // Bit 0 : 1 = short info (1st 4 Bytes) + u8 flags; /* Bit 0 : 1 = short info (1st 4 Bytes) */ } get_signalinfo; struct { @@ -312,43 +439,47 @@ struct mci_command { } get_iq_symbol; struct { - uint8_t flags; /* Bit 0 : 0 = VTM/SDR, 1 = SCAN, + u8 flags; /* Bit 0 : 0 = VTM/SDR, 1 = SCAN, Bit 1: 1 = Disable AGC, Bit 2: 1 = Set Gain. */ - uint8_t roll_off; - uint8_t rsvd1; - uint8_t rsvd2; - uint32_t frequency; - uint32_t symbol_rate; /* Only in VTM/SDR mode, SCAN Mode uses exactly 1550/24 MSymbols/s.*/ - uint8_t gain; /* Gain in 0.25 dB Steps */ + u8 roll_off; + u8 rsvd1; + u8 rsvd2; + u32 frequency; + u32 symbol_rate; /* Only in VTM/SDR mode, SCAN Mode uses exactly 1550/24 MSymbols/s.*/ + u8 gain; /* Gain in 0.25 dB Steps */ /* Frequency, symbolrate and gain can be schanged while running */ } sx8_start_iq; - + struct { - uint8_t flags; - /* Bit 0:1 Preamp Mode; 0 = Preamp AGC, 1 == Minimum (~ -17dB) , + u8 flags; + /* Bit 0:1 Preamp Mode; 0 = Preamp AGC, 1 == Minimum (~ -17dB) , 2 = Medium, 3 = Maximum gain {~ 15dB} Bit 2: Bypass Input LNA (6 dB less gain) (Note this is after Preamp) Bit 4: Set RF Gain Bit 5: Freeze RF Gain (Turn AGC off at current gain, only when already enabled) Bit 7: Optimize RF Gain and freeze for FFT */ - uint8_t rf_gain; /* 0 .. 50 dB */ + u8 rf_gain; /* 0 .. 50 dB */ } sx8_input_enable; - + struct { - u8 offset; // Offset into list, must be multiple of 64 - u8 select; // 0 = Slices, 1 = PLPs (C2 Only) - u8 data_slice; // DataSlice to get PLPList (C2 Only) + u8 offset; /* Offset into list, must be multiple of 64 */ + u8 select; /* 0 = Slices, 1 = PLPs (C2 Only) */ + u8 data_slice; /* DataSlice to get PLPList (C2 Only) */ } get_ids; struct { - u8 select; // 0 = Base, 1 = DataSilce, 2 = PLP, Bit 7: Set new ID - u8 id; // DataSliceID, PLPId + u8 select; /* 0 = Base, 1 = DataSilce, 2 = PLP, Bit 7: Set new ID */ + u8 id; /* DataSliceID, PLPId */ } get_l1_info; struct { - u8 select; // 0 = Data PLP, 1 = Common PLP, only DVB-T2 and DVB-C2 + u8 select; /* 0 = Data PLP, 1 = Common PLP, only DVB-T2 and DVB-C2 */ } get_bb_header; + + struct mod_setup_channels mod_setup_channels[4]; + struct mod_setup_stream mod_setup_stream; + struct mod_setup_output mod_setup_output; }; }; @@ -361,26 +492,27 @@ struct mci_result { u16 time; }; }; - + union { u32 result[27]; + u8 result8[27 * 4]; struct { u8 Rsvd0[3]; u8 Flags; - - u32 frequency; // actual frequency in Hz + + u32 frequency; /* actual frequency in Hz */ u32 rsvd1; - s16 channel_power; // channel power in dBm x 100 + s16 channel_power; /* channel power in dBm x 100 */ s16 rsvd2; - s16 signal_to_noise; // SNR in dB x 100, Note: negativ values are valid in DVB-S2 - s16 rsvd3; + s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */ + u16 signal_loss_counter;/* Counts signal losses and automatic retunes */ u32 rsvd4; - u32 ber_numerator; /* Bit error rate: PreRS in DVB-S, PreBCH in DVB-S2X */ - u32 ber_denominator; - u32 ber_rsvd1; // Place holder for modulation bit error rate + u32 ber_numerator; /* Bit error rate: PreRS in DVB-S, PreBCH in DVB-S2X */ + u32 ber_denominator; + u32 ber_rsvd1; /* Place holder for modulation bit error rate */ u32 ber_rsvd2; } common_signal_info; - + struct { u8 standard; /* 1 = DVB-S, 2 = DVB-S2X */ u8 pls_code; /* PLS code for DVB-S2/S2X, puncture rate for DVB-S */ @@ -394,7 +526,7 @@ struct mci_result { 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; + u32 ber_denominator; } dvbs2_signal_info; struct { @@ -409,7 +541,7 @@ struct mci_result { 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; + u32 ber_denominator; } isdbs_signal_info; struct { @@ -430,8 +562,8 @@ struct mci_result { struct { u8 modulation1; // bit 7..6: Constellation, bit 5..3 Hierachy, bit 2..0 CodeRate High u8 modulation2; // bit 7..5: CodeRate Low, bit 4..3 Guard Interval, bit 2..1 FFT Mode - u8 Rsvd0; - u8 Flags; + u8 rsvd0; + u8 flags; u32 frequency; /* actual frequency in Hz */ u32 rsvd1; s16 channel_power; /* channel power in dBm x 100 */ @@ -460,7 +592,7 @@ struct mci_result { struct { u8 rsvd0[3]; u8 flags; - + u32 frequency; // actual frequency in Hz u32 rsvd1; // s16 channel_power; // channel power in dBm x 100 @@ -469,7 +601,7 @@ struct mci_result { s16 rsvd2; u32 packet_errors; // Counter for packet errors. (set to 0 on Start command) u32 ber_numerator; // Bit error rate: PreBCH - u32 ber_denominator; + u32 ber_denominator; } dvbc2_signal_info; struct { @@ -492,51 +624,51 @@ struct mci_result { } isdbt_signal_info; struct { - u8 Constellation; - u8 Rsvd0[2]; - u8 Flags; - - u32 Frequency; // actual frequency in Hz - u32 SymbolRate; // actual symbolrate in Hz - s16 ChannelPower; // channel power in dBm x 100 - s16 BandPower; // band power in dBm x 100 - s16 SignalToNoise; // SNR in dB x 100, Note: negativ values are valid in DVB-S2 - s16 Rsvd2; - u32 PacketErrors; // Counter for packet errors. (set to 0 on Start command) - u32 BERNumerator; // Bit error rate: PreRS in DVB-S, PreBCH in DVB-S2X - u32 BERDenominator; - } ISDBC_SignalInfo; - + u8 constellation; + u8 rsvd0[2]; + u8 flags; + + 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; + } isdbc_signal_info; + struct { - u8 Constellation; - u8 Interleaving; - u8 Rsvd0; - u8 Flags; - - u32 Frequency; // actual frequency in Hz - u32 SymbolRate; // actual symbolrate in Hz - s16 ChannelPower; // channel power in dBm x 100 - s16 BandPower; // band power in dBm x 100 - s16 SignalToNoise; // SNR in dB x 100, Note: negativ values are valid in DVB-S2 - s16 Rsvd2; - u32 PacketErrors; // Counter for packet errors. (set to 0 on Start command) - u32 BERNumerator; // Bit error rate: PreRS in DVB-S, PreBCH in DVB-S2X - u32 BERDenominator; - } J83B_SignalInfo; - + u8 constellation; + u8 interleaving; + u8 rsvd0; + u8 flags; + + 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; + } j83b_signal_info; + struct { s16 i; s16 q; } iq_symbol; - + struct { - u8 TPSInfo[7]; - // uint16_t TPS_CellID; // Cell Identifier - } DVBT_TPSInfo; - + u8 tps_info[7]; + // u16 tps_cell_id; + } dvbt_tps_info; + struct { struct { - u8 Type; + u8 type; u8 BWExtension; u8 S1; u8 S2; @@ -561,7 +693,8 @@ struct mci_result { u8 CurrentRFIndex; u8 T2Version_PostScrambled_BaseLite_Rsvd[2]; // 4,1,1,4 bit u8 CRC32[4]; - } DVBT2_L1Pre; + } dvbt2_l1_pre; + struct { u8 SubSlicesPerFrame[2]; u8 NumPLP; @@ -572,9 +705,9 @@ struct mci_result { u8 FEFType; u8 FEFLength[3]; u8 FEFInterval; - } DVBT2_L1Post; - } DVBT2_L1Info; - + } dvbt2_l1_post; + } dvbt2_l1_info; + struct { u8 PLPID; u8 Type; @@ -593,8 +726,8 @@ struct mci_result { u8 TimeILType; u8 InBandAFlag; u8 InBandBFlag_Rsvd1_Mode_StaticFlag_StaticPaddingFlag[2]; // 1,11,2,1,1 - } DVBT2_PLPInfo; - + } dvbt2_plp_info; + struct { u8 NetworkID[2]; u8 C2SystemID[2]; @@ -613,13 +746,13 @@ struct mci_result { u8 ReservedTone; u8 Reserved4[2]; // EWS 1 bit, C2_Version 4 bit, Rsvd 11 bit } DVBC2_L1Part2; - + struct { u8 NumIDs; u8 Offset; u8 IDs[64]; } DVBC2_IDList; - + struct { u8 SliceID; u8 TunePosition[2]; @@ -633,7 +766,7 @@ struct mci_result { u8 NumPLP; u8 Reserved2; } DVBC2_SliceInfo; - + struct { u8 PLPID; u8 Bundled; @@ -649,20 +782,20 @@ struct mci_result { u8 OrginalNetworkID[2]; u8 Reserved1; } DVBC2_PLPInfo; - + struct { - u8 Valid; - u8 MATYPE_1; - u8 MATYPE_2; - u8 UPL[2]; - u8 DFL[2]; - u8 SYNC; - u8 SYNCD[2]; + u8 valid; + u8 matype_1; + u8 matype_2; + u8 upl[2]; + u8 dfl[2]; + u8 sync; + u8 syncd[2]; u8 rsvd; - u8 ISSY[3]; + u8 issy[3]; u8 min_input_stream_id; u8 max_input_stream_id; - } BBHeader; + } bb_header; struct { u8 Mode; // FFT Mode 1,2,3 @@ -684,9 +817,46 @@ struct mci_result { u8 Flags; // Bit 5: EWS flag, bit 4: Site Diversity flag, bit 3..1: Site Diversity information, bit 0: Extension flag u8 Extension[8]; // 61 bits, right aligned } ISDBS_TMCCInfo; + + struct { + u8 cut; + u8 avs_code; + u8 temperature; + u8 rsvd[13]; + } sx8_bist; + + struct { + u8 status; + u8 offset; + u8 length; + u8 rsvd2; + u32 rsvd3[2]; + u8 data[96]; + } SX8_packet_filter_status; + + struct { + u8 version; /* 0 = none, 1 = SX8 */ + u8 flags; /* Bit 0: 1 = Tuner Valid, Bit 1: 1 = Output Valid */ + u8 tuner; + u8 output; + } extended_status; + + struct { + u8 reserved; + u8 serial_number[17]; + } serial_number; + + struct { + u8 flags; + u8 serial_number[17]; + u16 code; + u8 ID[8]; + u8 LK[24]; + } license; + }; u32 version[3]; - u32 version_rsvd; + u8 version_rsvd; u8 version_major; u8 version_minor; u8 version_sub; @@ -763,13 +933,15 @@ struct mci_result { #define L1POST_STATIC_FLAG(p) (((p)[18] >> 1) & 0x01) #define L1POST_STATIC_PADDING_FLAG(p) (((p)[18] >> 1) & 0x01) +#ifdef __KERNEL__ + struct mci_base { struct list_head mci_list; void *key; struct ddb_link *link; - struct completion completion; +// struct completion completion; struct mutex tuner_lock; - struct mutex mci_lock; +// struct mutex mci_lock; int count; int type; }; @@ -795,16 +967,15 @@ struct mci_cfg { }; int ddb_mci_cmd(struct mci *state, struct mci_command *command, struct mci_result *result); -int ddb_mci_cmd_raw(struct mci *state, struct mci_command *command, u32 command_len, - struct mci_result *result, u32 result_len); -int ddb_mci_config(struct mci *state, u32 config); +int ddb_mci_cmd_link(struct ddb_link *link, struct mci_command *command, struct mci_result *result); int ddb_mci_get_status(struct mci *mci, struct mci_result *res); int ddb_mci_get_snr(struct dvb_frontend *fe); int ddb_mci_get_info(struct mci *mci); int ddb_mci_get_strength(struct dvb_frontend *fe); void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p); - -extern struct mci_cfg ddb_max_sx8_cfg; -extern struct mci_cfg ddb_max_m4_cfg; +int mci_init(struct ddb_link *link); +int mci_cmd_val(struct ddb_link *link, u32 cmd, u32 val); + +#endif #endif diff --git a/ddbridge/ddbridge-modulator.c b/ddbridge/ddbridge-modulator.c index cf12a8a..d2cabfe 100644 --- a/ddbridge/ddbridge-modulator.c +++ b/ddbridge/ddbridge-modulator.c @@ -23,8 +23,13 @@ #include "ddbridge.h" #include "ddbridge-io.h" +#include "ddbridge-ioctl.h" +#ifdef KERNEL_DVB_CORE +#include "../include/linux/dvb/mod.h" +#else #include +#endif #include /****************************************************************************/ @@ -164,11 +169,6 @@ static void mod_calc_rateinc(struct ddb_mod *mod) { u32 ri; - dev_info(mod->port->dev->dev, - "ibitrate %llu\n", mod->ibitrate); - dev_info(mod->port->dev->dev, - "obitrate %llu\n", mod->obitrate); - if (mod->ibitrate != 0) { u64 d = mod->obitrate - mod->ibitrate; @@ -195,6 +195,48 @@ static int mod_calc_obitrate(struct ddb_mod *mod) return 0; } +static int mod_set_stream(struct ddb_output *output) +{ + struct ddb *dev = output->port->dev; + u32 stream = output->nr; + struct ddb_mod *mod = &dev->mod[output->nr]; + struct ddb_link *link = &dev->link[0]; + struct mci_result res; + u32 channel; + struct mci_command cmd = { + .mod_command = MOD_SETUP_STREAM, + .mod_channel = stream, + .mod_stream = stream, + .mod_setup_stream = { + .standard = MOD_STANDARD_DVBC_8, + .symbol_rate = mod->symbolrate, + .qam = { + .modulation = mod->modulation - 1, + .rolloff = 13, + } + }, + }; + if (dev->link[0].info->version != 2) + return 0; + if (dev->link[0].ids.revision != 1) + return 0; + if ((dev->link[0].ids.hwid & 0xffffff) < 9065) + return 0; + if (!mod->frequency && !mod->symbolrate && !mod->modulation) + return 0; + + if (mod->frequency) + channel = (mod->frequency - 114000000) / 8000000; + if (!mod->symbolrate) + mod->symbolrate = 6900000; + if (!mod->modulation) + mod->modulation = 5; + cmd.mod_channel = channel; + cmd.mod_setup_stream.symbol_rate = mod->symbolrate; + cmd.mod_setup_stream.qam.modulation = mod->modulation - 1; + return ddb_mci_cmd_link(link, &cmd, &res); +} + static int mod_set_symbolrate(struct ddb_mod *mod, u32 srate) { struct ddb *dev = mod->port->dev; @@ -210,6 +252,7 @@ static int mod_set_symbolrate(struct ddb_mod *mod, u32 srate) } mod->symbolrate = srate; mod_calc_obitrate(mod); + mod_set_stream(mod->port->output); return 0; } @@ -227,6 +270,7 @@ static int mod_set_modulation(struct ddb_mod *mod, ddbwritel(dev, qamtab[modulation], CHANNEL_SETTINGS(mod->port->nr)); mod_calc_obitrate(mod); + mod_set_stream(mod->port->output); return 0; } @@ -241,6 +285,7 @@ static int mod_set_frequency(struct ddb_mod *mod, u32 frequency) if ((freq < 114) || (freq > 874)) return -EINVAL; mod->frequency = frequency; + mod_set_stream(mod->port->output); return 0; } @@ -322,14 +367,27 @@ int ddbridge_mod_output_start(struct ddb_output *output) CHANNEL_CONTROL(output->nr)); udelay(10); ddbwritel(dev, mod->Control, CHANNEL_CONTROL(output->nr)); - - if (dev->link[0].info->version == 2) { + switch (dev->link[0].info->version) { + case 2: + { u32 Output = (mod->frequency - 114000000) / 8000000; u32 KF = Symbolrate; u32 LF = 9000000UL; u32 d = gcd(KF, LF); u32 checkLF; + if ((dev->link[0].ids.revision == 1)) { + if ((dev->link[0].info->version == 2)) { + if ((dev->link[0].ids.hwid & 0xffffff) >= 9065) { + mod->Control |= CHANNEL_CONTROL_ENABLE_DVB; + break; + } + } else { + mod->Control |= CHANNEL_CONTROL_ENABLE_DVB; + break; + } + } + ddbwritel(dev, mod->modulation - 1, CHANNEL_SETTINGS(Channel)); ddbwritel(dev, Output, CHANNEL_SETTINGS2(Channel)); @@ -356,16 +414,21 @@ int ddbridge_mod_output_start(struct ddb_output *output) CHANNEL_CONTROL_CMD_SETUP)) return -EINVAL; mod->Control |= CHANNEL_CONTROL_ENABLE_DVB; - } else if (dev->link[0].info->version <= 1) { + break; + } + case 0: + case 1: /* QAM: 600 601 602 903 604 = 16 32 64 128 256 */ /* ddbwritel(dev, 0x604, CHANNEL_SETTINGS(output->nr)); */ ddbwritel(dev, qamtab[mod->modulation], CHANNEL_SETTINGS(output->nr)); mod->Control |= (CHANNEL_CONTROL_ENABLE_IQ | CHANNEL_CONTROL_ENABLE_DVB); - } else if (dev->link[0].info->version >= 16) { + break; + default: mod->Control |= (CHANNEL_CONTROL_ENABLE_IQ | CHANNEL_CONTROL_ENABLE_DVB); + break; } if (dev->link[0].info->version < 16) { mod_set_rateinc(dev, output->nr); @@ -622,7 +685,26 @@ static int mod_set_attenuator(struct ddb *dev, u32 Value) { if (Value > 31) return -EINVAL; - ddbwritel(dev, Value, RF_ATTENUATOR); + if (dev->link[0].ids.revision == 1) { + struct ddb_link *link = &dev->link[0]; + struct mci_result res; + struct mci_command cmd = { + .mod_command = MOD_SETUP_OUTPUT, + .mod_channel = 0, + .mod_stream = 0, + .mod_setup_output = { + .connector = MOD_CONNECTOR_F, + .num_channels = dev->link[0].info->port_num, + .unit = MOD_UNIT_DBUV, + .channel_power = 9000 - Value * 100, + }, + }; + if (!link->mci_ok) { + return -EFAULT; + } + return ddb_mci_cmd_link(link, &cmd, &res); + } else + ddbwritel(dev, Value, RF_ATTENUATOR); return 0; } @@ -1516,6 +1598,7 @@ static int mod3_set_ari(struct ddb_mod *mod, u32 rate) static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate) { + struct ddb *dev = mod->port->dev; u32 cic, inc, bypass = 0; switch (rate) { @@ -1556,19 +1639,52 @@ static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate) inc = 0x7684BD82; //1988410754; cic = 7; break; - case SYS_DVBS2_22: + case SYS_DVB_22: inc = 0x72955555; // 1922389333; cic = 5; bypass = 2; break; - case SYS_DVBS2_24: + case SYS_DVB_24: inc = 0x7d000000; cic = 5; bypass = 2; break; + case SYS_DVB_30: + inc = 0x7d000000; + cic = 4; + bypass = 2; + break; + case SYS_ISDBS_2886: + inc = 0x78400000; + cic = 4; + bypass = 2; + break; default: - return -EINVAL; + { + u64 a; + + if (rate < 1000000) + return -EINVAL; + if (rate > 30720000) + return -EINVAL; + + bypass = 2; + if (rate > 24576000) + cic = 4; + else if (rate > 20480000) + cic = 5; + else if (rate > 17554286) + cic = 6; + else if (rate > 15360000) + cic = 7; + else + cic = 8; + a = (1ULL << 31) * rate * 2 * cic; + inc = div_s64(a, 245760000); + break; } + } + dev_info(dev->dev, "inc = %08x, cic = %u, bypass = %u\n", inc, cic, bypass); ddbwritel(mod->port->dev, inc, SDR_CHANNEL_ARICW(mod->port->nr)); ddbwritel(mod->port->dev, (cic << 8) | (bypass << 4), SDR_CHANNEL_CONFIG(mod->port->nr)); @@ -1596,6 +1712,7 @@ static int mod3_prop_proc(struct ddb_mod *mod, struct dtv_property *tvp) case MODULATOR_GAIN: return mod_set_sdr_gain(mod->port->dev, tvp->u.data); + } return -EINVAL; } @@ -1618,7 +1735,11 @@ static int mod_prop_proc(struct ddb_mod *mod, struct dtv_property *tvp) return mod_set_attenuator(mod->port->dev, tvp->u.data); case MODULATOR_INPUT_BITRATE: +#ifdef KERNEL_DVB_CORE + return mod_set_ibitrate(mod, *(u64 *) &tvp->u.buffer.data[0]); +#else return mod_set_ibitrate(mod, tvp->u.data64); +#endif case MODULATOR_GAIN: if (mod->port->dev->link[0].info->version == 2) @@ -1717,7 +1838,8 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg) (struct dtv_properties __user *) parg; int i, ret = 0; - if (dev->link[0].info->version >= 16 && cmd != FE_SET_PROPERTY) + if (dev->link[0].info->version >= 16 && + (cmd != FE_SET_PROPERTY && cmd != IOCTL_DDB_MCI_CMD)) return -EINVAL; mutex_lock(&dev->ioctl_mutex); switch (cmd) { @@ -1809,6 +1931,27 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg) mod->pcr_correction = cp->pcr_correction; break; } + case IOCTL_DDB_MCI_CMD: + { + struct ddb_mci_msg *msg = + (struct ddb_mci_msg __user *) parg; + struct ddb_link *link; + + if (dev->link[0].ids.revision != 1) + break; + + if (msg->link > 3) { + ret = -EFAULT; + break; + } + link = &dev->link[msg->link]; + if (!link->mci_ok) { + ret = -EFAULT; + break; + } + ret = ddb_mci_cmd_link(link, &msg->cmd, &msg->res); + break; + } default: ret = -EINVAL; break; @@ -1817,6 +1960,18 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg) return ret; } +static int mod_init_2_1(struct ddb *dev, u32 Frequency) +{ + int i, streams = dev->link[0].info->port_num; + + dev->mod_base.frequency = Frequency; + for (i = 0; i < streams; i++) { + struct ddb_mod *mod = &dev->mod[i]; + mod->port = &dev->port[i]; + } + return 0; +} + static int mod_init_2(struct ddb *dev, u32 Frequency) { int i, status, streams = dev->link[0].info->port_num; @@ -1991,18 +2146,21 @@ static int mod_init_sdr_iq(struct ddb *dev) ret = rfdac_init(dev); if (ret) dev_err(dev->dev, "RFDAC setup failed\n"); - + ddbwritel(dev, 0x01, 0x240); + //mod3_set_base_frequency(dev, 602000000); dev->mod_base.frequency = 570000000; for (i = 0; i < streams; i++) { struct ddb_mod *mod = &dev->mod[i]; mod->port = &dev->port[i]; - ddbwritel(dev, 0x00, SDR_CHANNEL_CONTROL(i)); + if (dev->link[0].ids.revision != 1) + ddbwritel(dev, 0x00, SDR_CHANNEL_CONTROL(i)); } - + if (dev->link[0].ids.revision == 1) + return ret; mod_set_sdr_attenuator(dev, 0); udelay(10); mod_set_sdr_gain(dev, 120); @@ -2011,6 +2169,25 @@ static int mod_init_sdr_iq(struct ddb *dev) int ddbridge_mod_init(struct ddb *dev) { + dev_info(dev->dev, "Revision: %u\n", dev->link[0].ids.revision); + if (dev->link[0].ids.revision == 1) { + switch (dev->link[0].info->version) { + case 0: + case 1: + return mod_init_1(dev, 722000000); + case 2: /* FSM */ + if ((dev->link[0].ids.hwid & 0xffffff) >= 9065) + return mod_init_2_1(dev, 114000000); + return mod_init_2(dev, 114000000); + case 16: /* PAL */ + return mod_init_3(dev, 503250000); + case 17: /* raw IQ */ + case 18: /* IQ+FFT */ + return mod_init_sdr_iq(dev); + default: + return -1; + } + } switch (dev->link[0].info->version) { case 0: case 1: diff --git a/ddbridge/ddbridge-regs.h b/ddbridge/ddbridge-regs.h index 61216a8..73f172e 100644 --- a/ddbridge/ddbridge-regs.h +++ b/ddbridge/ddbridge-regs.h @@ -260,8 +260,8 @@ #define LNB_CMD_DISEQC 6 #define LNB_CMD_SCIF 7 -#define LNB_BUSY BIT_ULL(4) -#define LNB_TONE BIT_ULL(15) +#define LNB_BUSY (1ULL << 4) +#define LNB_TONE (1ULL << 15) #define LNB_INTERRUPT_BASE 4 diff --git a/ddbridge/ddbridge-sx8.c b/ddbridge/ddbridge-sx8.c index 3566d54..84f7a3d 100644 --- a/ddbridge/ddbridge-sx8.c +++ b/ddbridge/ddbridge-sx8.c @@ -23,13 +23,24 @@ #include "ddbridge.h" #include "ddbridge-io.h" -#include "ddbridge-i2c.h" #include "ddbridge-mci.h" static int default_mod = 3; module_param(default_mod, int, 0444); MODULE_PARM_DESC(default_mod, "default modulations enabled, default is 3 (1 = QPSK, 2 = 8PSK, 4 = 16APSK, ...)"); +static int direct_mode; +module_param(direct_mode, int, 0444); +MODULE_PARM_DESC(direct_mode, "Ignore LDPC limits and assign high speed demods according to needed symbolrate."); + +static u32 sx8_tuner_flags; +module_param(sx8_tuner_flags, int, 0664); +MODULE_PARM_DESC(sx8_tuner_flags, "Change SX8 tuner flags."); + +static u32 sx8_tuner_gain; +module_param(sx8_tuner_gain, int, 0664); +MODULE_PARM_DESC(sx8_tuner_gain, "Change SX8 tuner gain."); + static const u32 MCLK = (1550000000 / 12); /* Add 2MBit/s overhead allowance (minimum factor is 90/32400 for QPSK w/o Pilots) */ @@ -44,25 +55,19 @@ struct sx8_base { struct mci_base mci_base; u8 tuner_use_count[SX8_TUNER_NUM]; - u32 gain_mode[SX8_TUNER_NUM]; u32 used_ldpc_bitrate[SX8_DEMOD_NUM]; u8 demod_in_use[SX8_DEMOD_NUM]; u32 iq_mode; - u32 burst_size; - u32 direct_mode; }; struct sx8 { struct mci mci; + struct mutex lock; int first_time_lock; int started; int iq_started; - - u32 bb_mode; - u32 local_frequency; - }; static const u8 dvbs2_bits_per_symbol[] = { @@ -114,47 +119,73 @@ static void release(struct dvb_frontend *fe) kfree(state); } +static int ddb_mci_tsconfig(struct mci *state, u32 config) +{ + struct ddb_link *link = state->base->link; + + if (link->ids.device != 0x0009 && link->ids.device != 0x000b) + return -EINVAL; + ddblwritel(link, config, SX8_TSCONFIG); + return 0; +} + static int read_status(struct dvb_frontend *fe, enum fe_status *status) { - int stat; + int stat = 0; 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 dtv_frontend_properties *p = &fe->dtv_property_cache; struct mci_result res; + *status = 0x00; + mutex_lock(&state->lock); + if (!state->started && !state->iq_started) + goto unlock; stat = ddb_mci_get_status(&state->mci, &res); if (stat) - return stat; - *status = 0x00; + goto unlock; ddb_mci_get_info(&state->mci); - if (res.status == SX8_DEMOD_WAIT_MATYPE) - *status = 0x0f; - if (res.status == MCI_DEMOD_LOCKED) { - *status = 0x1f; - if (state->mci.signal_info.dvbs2_signal_info.standard == 2) { - sx8_base->used_ldpc_bitrate[state->mci.nr] = - p->symbol_rate * - dvbs2_bits_per_symbol[ - state->mci.signal_info. - dvbs2_signal_info.pls_code]; - } else - sx8_base->used_ldpc_bitrate[state->mci.nr] = 0; - } + if (stat) + goto unlock; + if (res.status == MCI_DEMOD_LOCKED || res.status == SX8_DEMOD_IQ_MODE) { + *status = FE_HAS_LOCK | FE_HAS_SYNC | FE_HAS_VITERBI | + FE_HAS_CARRIER | FE_HAS_SIGNAL; + if (res.status == MCI_DEMOD_LOCKED) { + mutex_lock(&mci_base->tuner_lock); + if (state->first_time_lock && state->started) { + if (state->mci.signal_info.dvbs2_signal_info.standard == 2) { + sx8_base->used_ldpc_bitrate[state->mci.nr] = + p->symbol_rate * + dvbs2_bits_per_symbol[ + state->mci.signal_info. + dvbs2_signal_info.pls_code]; + } else + sx8_base->used_ldpc_bitrate[state->mci.nr] = 0; + state->first_time_lock = 0; + } + mutex_unlock(&mci_base->tuner_lock); + } + } else if (res.status == MCI_DEMOD_TIMEOUT) + *status = FE_TIMEDOUT; + else if (res.status >= SX8_DEMOD_WAIT_MATYPE) + *status = FE_HAS_SYNC | FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL; +unlock: + mutex_unlock(&state->lock); return stat; } -static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on) +static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on, + u8 flags, u8 gain) { 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; memset(&cmd, 0, sizeof(cmd)); cmd.tuner = state->mci.tuner; cmd.command = on ? SX8_CMD_INPUT_ENABLE : SX8_CMD_INPUT_DISABLE; - cmd.sx8_input_enable.flags = sx8_base->gain_mode[state->mci.tuner]; + cmd.sx8_input_enable.flags = flags; + cmd.sx8_input_enable.rf_gain = gain; return ddb_mci_cmd(&state->mci, &cmd, NULL); } @@ -172,20 +203,20 @@ static int stop_iq(struct dvb_frontend *fe) cmd.command = SX8_CMD_STOP_IQ; cmd.demod = state->mci.demod; ddb_mci_cmd(&state->mci, &cmd, NULL); - ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL); + ddb_mci_tsconfig(&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); + mci_set_tuner(fe, input, 0, 0, 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; + mutex_unlock(&mci_base->tuner_lock); sx8_base->iq_mode = 0; state->iq_started = 0; - mutex_unlock(&mci_base->tuner_lock); return 0; } @@ -195,12 +226,13 @@ static int stop(struct dvb_frontend *fe) struct mci_base *mci_base = state->mci.base; struct sx8_base *sx8_base = (struct sx8_base *) mci_base; struct mci_command cmd; - u32 input = state->mci.tuner; + u32 input; + input = state->mci.tuner; if (!state->started) return -1; - memset(&cmd, 0, sizeof(cmd)); if (state->mci.demod != SX8_DEMOD_NONE) { + memset(&cmd, 0, sizeof(cmd)); cmd.command = MCI_CMD_STOP; cmd.demod = state->mci.demod; ddb_mci_cmd(&state->mci, &cmd, NULL); @@ -209,24 +241,29 @@ static int stop(struct dvb_frontend *fe) cmd.demod = state->mci.demod; cmd.output = 0; ddb_mci_cmd(&state->mci, &cmd, NULL); - ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL); + ddb_mci_tsconfig(&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); + mci_set_tuner(fe, input, 0, 0, 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; - mutex_unlock(&mci_base->tuner_lock); state->started = 0; + mutex_unlock(&mci_base->tuner_lock); return 0; } +static const u8 ro_lut[8] = { + 8 | SX8_ROLLOFF_35, 8 | SX8_ROLLOFF_20, 8 | SX8_ROLLOFF_25, 0, + 8 | SX8_ROLLOFF_15, 8 | SX8_ROLLOFF_10, 8 | SX8_ROLLOFF_05, 0, +}; + static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config) { struct sx8 *state = fe->demodulator_priv; @@ -268,7 +305,7 @@ static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config) goto unlock; } - if (sx8_base->direct_mode) { + if (direct_mode) { if (p->symbol_rate >= MCLK / 2) { if (state->mci.nr < 4) i = state->mci.nr; @@ -290,16 +327,15 @@ static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config) free_ldpc_bitrate = MAX_LDPC_BITRATE - used_ldpc_bitrate; if (free_ldpc_bitrate > MAX_DEMOD_LDPC_BITRATE) free_ldpc_bitrate = MAX_DEMOD_LDPC_BITRATE; - + while (p->symbol_rate * bits_per_symbol > free_ldpc_bitrate) bits_per_symbol--; if (bits_per_symbol < 2) { stat = -EBUSY; goto unlock; } - modmask &= ((1 << (bits_per_symbol - 1)) - 1); - if( ((flags & 0x02) != 0) && (modmask == 0)) { + if (((flags & 0x02) != 0) && (modmask == 0)) { stat = -EBUSY; goto unlock; } @@ -317,7 +353,7 @@ static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config) state->mci.demod = i; if (!sx8_base->tuner_use_count[input]) - mci_set_tuner(fe, input, 1); + mci_set_tuner(fe, input, 1, sx8_tuner_flags, sx8_tuner_gain); sx8_base->tuner_use_count[input]++; sx8_base->iq_mode = (ts_config > 1); unlock: @@ -325,13 +361,12 @@ unlock: if (stat) return stat; memset(&cmd, 0, sizeof(cmd)); - if (sx8_base->iq_mode) { cmd.command = SX8_CMD_ENABLE_IQOUTPUT; cmd.demod = state->mci.demod; - cmd.output = p->stream_id & 7; + cmd.output = p->stream_id & 0x0f; ddb_mci_cmd(&state->mci, &cmd, NULL); - ddb_mci_config(&state->mci, ts_config); + ddb_mci_tsconfig(&state->mci, ts_config); } if (p->stream_id != NO_STREAM_ID_FILTER && !(p->stream_id & 0xf0000000)) flags |= 0x80; @@ -345,6 +380,7 @@ unlock: cmd.command = MCI_CMD_SEARCH_DVBS; cmd.dvbs2_search.flags = flags; cmd.dvbs2_search.s2_modulation_mask = modmask; + cmd.dvbs2_search.rsvd1 = ro_lut[p->rolloff & 7]; cmd.dvbs2_search.retry = 2; cmd.dvbs2_search.frequency = p->frequency * 1000; cmd.dvbs2_search.symbol_rate = p->symbol_rate; @@ -358,6 +394,9 @@ unlock: (p->stream_id & 0x80000000)) cmd.output |= 0x80; stat = ddb_mci_cmd(&state->mci, &cmd, NULL); + state->started = 1; + state->first_time_lock = 1; + state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL; if (stat) stop(fe); return stat; @@ -365,7 +404,7 @@ unlock: static int start_iq(struct dvb_frontend *fe, u32 flags, - u32 roll_off, u32 ts_config) + u32 ts_config) { struct sx8 *state = fe->demodulator_priv; struct mci_base *mci_base = state->mci.base; @@ -376,8 +415,8 @@ static int start_iq(struct dvb_frontend *fe, u32 flags, u32 input = state->mci.tuner; int i, stat = 0; + mutex_lock(&mci_base->tuner_lock); if (!state->iq_started) { - mutex_lock(&mci_base->tuner_lock); if (sx8_base->iq_mode) { stat = -EBUSY; goto unlock; @@ -390,28 +429,36 @@ static int start_iq(struct dvb_frontend *fe, u32 flags, 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; + sx8_base->iq_mode = 2; + mci_set_tuner(fe, input, 1, flags & 0xff, 0x40); + } else { + if ((state->iq_started & 0x07) != state->mci.nr) { + stat = -EBUSY; + goto unlock; + } } +unlock: + mutex_unlock(&mci_base->tuner_lock); + if (stat) + return stat; memset(&cmd, 0, sizeof(cmd)); cmd.command = SX8_CMD_START_IQ; - cmd.sx8_start_iq.flags = flags >> 8; - cmd.sx8_start_iq.roll_off = roll_off; + cmd.sx8_start_iq.flags = (flags >> 16) & 0xff; + cmd.sx8_start_iq.roll_off = 5; + //cmd.sx8_start_iq.roll_off = ro_lut[p->rolloff & 7]; cmd.sx8_start_iq.frequency = p->frequency * 1000; cmd.sx8_start_iq.symbol_rate = p->symbol_rate; - cmd.sx8_start_iq.gain = flags & 0xff; + cmd.sx8_start_iq.gain = (flags >> 8) & 0xff; cmd.tuner = state->mci.tuner; cmd.demod = state->mci.demod; stat = ddb_mci_cmd(&state->mci, &cmd, NULL); + state->iq_started = 8 | state->mci.nr; + state->first_time_lock = 1; + state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL; if (stat) stop_iq(fe); - ddb_mci_config(&state->mci, ts_config); + ddb_mci_tsconfig(&state->mci, ts_config); return stat; } @@ -421,7 +468,6 @@ static int set_lna(struct dvb_frontend *fe) return 0; } - static int set_parameters(struct dvb_frontend *fe) { int stat = 0; @@ -437,6 +483,7 @@ static int set_parameters(struct dvb_frontend *fe) state->mci.input->con = ts_mode << 8; if (iq_mode) ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ); + mutex_lock(&state->lock); stop(fe); if (iq_mode < 2) { u32 mask; @@ -463,19 +510,10 @@ static int set_parameters(struct dvb_frontend *fe) break; } stat = start(fe, 3, mask, ts_config); - if (!stat) { - state->started = 1; - state->first_time_lock = 1; - state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL; - } } else { - stat = start_iq(fe, (isi >> 8) & 0xffff, 4, ts_config); - if (!stat) { - state->iq_started = 1; - state->first_time_lock = 1; - state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL; - } + stat = start_iq(fe, isi & 0xffffff, ts_config); } + mutex_unlock(&state->lock); return stat; } @@ -514,16 +552,25 @@ static int set_input(struct dvb_frontend *fe, int input) return -EINVAL; if (state->mci.tuner == input) return 0; + mutex_lock(&state->lock); stop_iq(fe); stop(fe); - state->mci.tuner = p->input = input; + state->mci.tuner = input; +#ifndef KERNEL_DVB_CORE + p->input = input; +#endif + mutex_unlock(&state->lock); return 0; } static int sleep(struct dvb_frontend *fe) { + struct sx8 *state = fe->demodulator_priv; + + mutex_lock(&state->lock); stop_iq(fe); stop(fe); + mutex_unlock(&state->lock); return 0; } @@ -537,7 +584,6 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties static struct dvb_frontend_ops sx8_ops = { .delsys = { SYS_DVBS, SYS_DVBS2 }, - .xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */ .info = { .name = "DVB-S/S2X", .frequency_min_hz = 950000000, @@ -557,7 +603,10 @@ static struct dvb_frontend_ops sx8_ops = { .tune = tune, .release = release, .read_status = read_status, +#ifndef KERNEL_DVB_CORE + .xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */ .set_input = set_input, +#endif .set_lna = set_lna, .sleep = sleep, }; @@ -567,8 +616,11 @@ static int init(struct mci *mci) struct sx8 *state = (struct sx8 *) mci; state->mci.demod = SX8_DEMOD_NONE; +#ifndef KERNEL_DVB_CORE mci->fe.ops.xbar[1] = mci->nr; mci->fe.dtv_property_cache.input = mci->tuner; +#endif + mutex_init(&state->lock); return 0; } @@ -579,7 +631,7 @@ static int base_init(struct mci_base *mci_base) return 0; } -struct mci_cfg ddb_max_sx8_cfg = { +static struct mci_cfg ddb_max_sx8_cfg = { .type = 0, .fe_ops = &sx8_ops, .base_size = sizeof(struct sx8_base), @@ -587,3 +639,10 @@ struct mci_cfg ddb_max_sx8_cfg = { .init = init, .base_init = base_init, }; + +struct dvb_frontend *ddb_sx8_attach(struct ddb_input *input, int nr, int tuner, + int (**fn_set_input)(struct dvb_frontend *fe, int input)) +{ + *fn_set_input = set_input; + return ddb_mci_attach(input, &ddb_max_sx8_cfg, nr, tuner); +} diff --git a/ddbridge/ddbridge.h b/ddbridge/ddbridge.h index 9170dfc..b1d3a14 100644 --- a/ddbridge/ddbridge.h +++ b/ddbridge/ddbridge.h @@ -23,9 +23,6 @@ #ifndef _DDBRIDGE_H_ #define _DDBRIDGE_H_ -#define DDB_USE_WORK -/*#define DDB_TEST_THREADED*/ - #include #if (KERNEL_VERSION(3, 8, 0) <= LINUX_VERSION_CODE) @@ -114,6 +111,7 @@ struct ddb_regmap { u32 irq_base_odma; u32 irq_base_gtl; u32 irq_base_rate; + u32 irq_base_mci; const struct ddb_regset *i2c; const struct ddb_regset *i2c_buf; @@ -127,6 +125,9 @@ struct ddb_regmap { const struct ddb_regset *channel; const struct ddb_regset *gtl; + + const struct ddb_regset *mci; + const struct ddb_regset *mci_buf; }; struct ddb_ids { @@ -139,6 +140,7 @@ struct ddb_ids { u32 regmapid; u32 devid; u32 mac; + u8 revision; }; struct ddb_info { @@ -200,11 +202,7 @@ struct ddb_dma { u32 div; u32 bufval; -#ifdef DDB_USE_WORK - struct work_struct work; -#else struct tasklet_struct tasklet; -#endif spinlock_t lock; /* DMA lock */ wait_queue_head_t wq; int running; @@ -215,6 +213,7 @@ struct ddb_dma { u32 stall_count; u32 packet_loss; + u32 unaligned; }; struct ddb_dvb { @@ -427,6 +426,9 @@ struct ddb_link { struct ddb_irq irq[256]; struct mci_base *mci_base; + struct completion mci_completion; + struct mutex mci_lock; + int mci_ok; }; struct ddb { diff --git a/ddbridge/dvb_netstream.c b/ddbridge/dvb_netstream.c index f49fc96..ee1188b 100644 --- a/ddbridge/dvb_netstream.c +++ b/ddbridge/dvb_netstream.c @@ -26,6 +26,9 @@ #include #include "dvb_netstream.h" +int ddb_dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, + int (*func)(struct file *file, unsigned int cmd, void *arg)); + static ssize_t ns_write(struct file *file, const char *buf, size_t count, loff_t *ppos) { @@ -211,7 +214,7 @@ static int do_ioctl(struct file *file, unsigned int cmd, void *parg) static long ns_ioctl(struct file *file, unsigned int cmd, unsigned long arg) { - return dvb_usercopy(file, cmd, arg, do_ioctl); + return ddb_dvb_usercopy(file, cmd, arg, do_ioctl); } static const struct file_operations ns_fops = { diff --git a/ddbridge/dvb_netstream.h b/ddbridge/dvb_netstream.h index ca2a0a5..d6ed26d 100644 --- a/ddbridge/dvb_netstream.h +++ b/ddbridge/dvb_netstream.h @@ -36,7 +36,7 @@ #include #include #include -#include +#include "ns.h" #include diff --git a/ddbridge/ns.h b/ddbridge/ns.h new file mode 100644 index 0000000..9991375 --- /dev/null +++ b/ddbridge/ns.h @@ -0,0 +1,76 @@ +#ifndef _UAPI_DVBNS_H_ +#define _UAPI_DVBNS_H_ + +#include + +struct dvb_ns_params { + __u8 smac[6]; + __u8 dmac[6]; + __u8 sip[16]; + __u8 dip[16]; + __u16 sport; + __u16 dport; + __u16 sport2; + __u16 dport2; + __u8 ssrc[8]; + __u8 flags; + __u8 qos; + __u16 vlan; + __u8 ttl; +}; + +#define DVB_NS_IPV6 0x01 +#define DVB_NS_RTP 0x02 +#define DVB_NS_RTCP 0x04 +#define DVB_NS_RTP_TO 0x08 +#define DVB_NS_VLAN 0x10 + +struct dvb_ns_rtcp { + __u8 *msg; + __u16 len; +}; + +struct dvb_ns_packet { + __u8 *buf; + __u8 count; +}; + +struct dvb_nsd_ts { + __u16 pid; + __u16 num; + __u16 input; + __u16 timeout; + __u16 len; + __u8 *ts; + __u8 mode; + __u8 table; + + __u8 filter_mask; + __u8 section; + __u16 section_id; +}; + +struct dvb_ns_cap { + __u8 streams_max; + __u8 reserved[127]; +}; + +#define NS_SET_NET _IOW('o', 192, struct dvb_ns_params) +#define NS_START _IO('o', 193) +#define NS_STOP _IO('o', 194) +#define NS_SET_PID _IOW('o', 195, __u16) +#define NS_SET_PIDS _IOW('o', 196, __u8 *) +#define NS_SET_RTCP_MSG _IOW('o', 197, struct dvb_ns_rtcp) + +#define NSD_START_GET_TS _IOWR('o', 198, struct dvb_nsd_ts) +#define NSD_STOP_GET_TS _IOWR('o', 199, struct dvb_nsd_ts) +#define NSD_CANCEL_GET_TS _IO('o', 200) +#define NSD_POLL_GET_TS _IOWR('o', 201, struct dvb_nsd_ts) + +#define NS_SET_PACKETS _IOW('o', 202, struct dvb_ns_packet) +#define NS_INSERT_PACKETS _IOW('o', 203, __u8) +#define NS_SET_CI _IOW('o', 204, __u8) + +#define NS_GET_CAP _IOR('o', 204, struct dvb_ns_cap)) + +#endif /*_UAPI_DVBNS_H_*/ diff --git a/docs/firmware b/docs/firmware new file mode 100644 index 0000000..6bc8b76 --- /dev/null +++ b/docs/firmware @@ -0,0 +1,13 @@ +Firmware update: + +Copy the firmware file to the dddvb/apps/ directory and +execute "./flashprog". + +The program will try to identify the card version and +check if it finds the corresponding firmware file. +It will then prompt you to confirm to proceed +with the flashing procedure. + +After the update the system needs a power cycle. + + diff --git a/docs/iq_samples b/docs/iq_samples new file mode 100644 index 0000000..86a4fa4 --- /dev/null +++ b/docs/iq_samples @@ -0,0 +1,27 @@ +~The Max SX8 can provide IQ samples in real time. + +They are 8 bit signed values embedded in TS packets with PID 0x200. + +API: + +Currently DTV_STREAM_ID is misused. + +0x10000000 - symbols (locked and tracked) at symbol rate +0x20000000 - samples at symbol rate + (fixed at ADC rate (1550/24=64.583... MHz) if 0x00010000 is set) + Max. sample rate is 64.583333 MHz. + +0x00xx0000 - flags + Bit 0 : 0 = VTM/SDR, 1 = SCAN, + Bit 1: 1 = Disable channel AGC, + Bit 2: 1 = Set Gain. + +0x0000xx00 - xx=gain + +0x000000xx - xx=flags + Bit 0:1 Preamp Mode; 0 = Preamp AGC, 1 == Minimum (~ -17dB) , + 2 = Medium, 3 = Maximum gain {~ 15dB} + Bit 2: Bypass Input LNA (6 dB less gain) (Note this is after Preamp) + Bit 4: Set RF Gain + Bit 5: Freeze RF Gain (Turn AGC off at current gain, only when already enabled) + Bit 7: Optimize RF Gain and freeze for FFT diff --git a/docs/redirect b/docs/redirect index db5ca9b..ec3337d 100644 --- a/docs/redirect +++ b/docs/redirect @@ -28,3 +28,7 @@ devices in any way. adapter_alloc=3 is rcommended when using redirect The ci device will then show up in the same adapter directory and most software will then assume it belongs to the frontend in the same directory. + + +Redirect between cards in different IOMMU groups will not work! +Disable IOMMU if you have this problem. \ No newline at end of file diff --git a/dvb-core/Makefile b/dvb-core/Makefile index 28e3437..c9ff666 100644 --- a/dvb-core/Makefile +++ b/dvb-core/Makefile @@ -13,4 +13,3 @@ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \ obj-$(CONFIG_DVB_CORE) += dvb-core.o EXTRA_CFLAGS += -DCONFIG_DVB_DYNAMIC_MINORS -DCONFIG_DVB_NET -#NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux diff --git a/dvb-core/Makefile.kernel b/dvb-core/Makefile.kernel index 51d161a..0814bc9 100644 --- a/dvb-core/Makefile.kernel +++ b/dvb-core/Makefile.kernel @@ -11,3 +11,4 @@ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ obj-$(CONFIG_DVB_CORE) += dvb-core.o ccflags-y += -Idrivers/media/dvb-core/ +ccflags-y += --include=dd_compat.h diff --git a/dvb-core/dmxdev.c b/dvb-core/dmxdev.c index 6d09853..36a2fe2 100644 --- a/dvb-core/dmxdev.c +++ b/dvb-core/dmxdev.c @@ -479,6 +479,9 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, u32 *buffer_flags) { struct dmxdev_filter *dmxdevfilter = feed->priv; +#ifdef CONFIG_DVB_MMAP + struct dvb_vb2_ctx *ctx; +#endif struct dvb_ringbuffer *buffer; int ret; @@ -766,7 +769,7 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter) ret = dmxdev->demux->allocate_section_feed(dmxdev->demux, secfeed, dvb_dmxdev_section_callback); - if (ret < 0) { + if (!*secfeed) { pr_err("DVB (%s): could not alloc feed\n", __func__); return ret; diff --git a/dvb-core/dvb_ca_en50221.c b/dvb-core/dvb_ca_en50221.c index c398c39..ed59c5a 100644 --- a/dvb-core/dvb_ca_en50221.c +++ b/dvb-core/dvb_ca_en50221.c @@ -194,10 +194,10 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca); static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 *ebuf, int ecount); static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, - u8 *ebuf, int ecount); + u8 *ebuf, int ecount, u8 flags); /** - * Safely find needle in haystack. + * findstr - Safely find needle in haystack. * * @haystack: Buffer to look in. * @hlen: Number of bytes in haystack. @@ -377,7 +377,7 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) ret = dvb_ca_en50221_wait_if_status(ca, slot, STATUSREG_FR, HZ / 10); if (ret) return ret; - ret = dvb_ca_en50221_write_data(ca, slot, buf, 2); + ret = dvb_ca_en50221_write_data(ca, slot, buf, 2, CMDREG_SW); if (ret != 2) return -EIO; ret = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); @@ -629,8 +629,8 @@ static int dvb_ca_en50221_set_configoption(struct dvb_ca_private *ca, int slot) * @ca: CA instance. * @slot: Slot to read from. * @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. * * return: Number of bytes read, or < 0 on error @@ -783,20 +783,20 @@ exit: * @ca: CA instance. * @slot: Slot to write to. * @buf: The data in this buffer is treated as a complete link-level packet to - * be written. + * be written. * @bytes_write: Size of ebuf. * * return: Number of bytes written, or < 0 on error. */ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, - u8 *buf, int bytes_write) + u8 *buf, int bytes_write, u8 flags) { struct dvb_ca_slot *sl = &ca->slot_info[slot]; int status; int i; dprintk("%s\n", __func__); - + flags=0; /* sanity check */ if (bytes_write > sl->link_buf_size) return -EINVAL; @@ -824,7 +824,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, /* OK, set HC bit */ status = ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, - IRQEN | CMDREG_HC); + IRQEN | CMDREG_HC | flags); if (status) goto exit; @@ -894,7 +894,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, buf[0], (buf[1] & 0x80) == 0, bytes_write); exit: - ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN); + ca->pub->write_cam_control(ca->pub, slot, CTRLIF_COMMAND, IRQEN | flags); exitnowrite: return status; @@ -1013,7 +1013,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_frda_irq); /* EN50221 thread functions */ /** - * Wake up the DVB CA thread + * dvb_ca_en50221_thread_wakeup - Wake up the DVB CA thread * * @ca: CA instance. */ @@ -1027,7 +1027,7 @@ static void dvb_ca_en50221_thread_wakeup(struct dvb_ca_private *ca) } /** - * Update the delay used by the thread. + * dvb_ca_en50221_thread_update_delay - Update the delay used by the thread. * * @ca: CA instance. */ @@ -1085,7 +1085,7 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) } /** - * Poll if the CAM is gone. + * dvb_ca_en50221_poll_cam_gone - Poll if the CAM is gone. * * @ca: CA instance. * @slot: Slot to process. @@ -1116,7 +1116,8 @@ static int dvb_ca_en50221_poll_cam_gone(struct dvb_ca_private *ca, int slot) } /** - * Thread state machine for one CA slot to perform the data transfer. + * dvb_ca_en50221_thread_state_machine - Thread state machine for one CA slot + * to perform the data transfer. * * @ca: CA instance. * @slot: Slot to process. @@ -1268,7 +1269,7 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca, sl->slot_state = DVB_CA_SLOTSTATE_RUNNING; dvb_ca_en50221_thread_update_delay(ca); pr_info("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", - ca->dvbdev->adapter->num); + ca->dvbdev->adapter->num); break; case DVB_CA_SLOTSTATE_RUNNING: @@ -1347,13 +1348,14 @@ static int dvb_ca_en50221_thread(void *data) /* EN50221 IO interface functions */ /** - * Real ioctl implementation. - * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. + * dvb_ca_en50221_io_do_ioctl - Real ioctl implementation. * * @file: File concerned. * @cmd: IOCTL command. * @parg: Associated argument. * + * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. + * * return: 0 on success, <0 on error. */ static int dvb_ca_en50221_io_do_ioctl(struct file *file, @@ -1407,7 +1409,9 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file, err = -EINVAL; goto out_unlock; } - +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18)) + slot = array_index_nospec(slot, ca->slot_count); +#endif info->type = CA_CI_LINK; info->flags = 0; sl = &ca->slot_info[slot]; @@ -1431,7 +1435,7 @@ out_unlock: } /** - * Wrapper for ioctl implementation. + * dvb_ca_en50221_io_ioctl - Wrapper for ioctl implementation. * * @file: File concerned. * @cmd: IOCTL command. @@ -1446,7 +1450,7 @@ static long dvb_ca_en50221_io_ioctl(struct file *file, } /** - * Implementation of write() syscall. + * dvb_ca_en50221_io_write - Implementation of write() syscall. * * @file: File structure. * @buf: Source buffer. @@ -1529,7 +1533,7 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, mutex_lock(&sl->slot_lock); status = dvb_ca_en50221_write_data(ca, slot, fragbuf, - fraglen + 2); + fraglen + 2, 0); mutex_unlock(&sl->slot_lock); if (status == (fraglen + 2)) { written = 1; @@ -1603,7 +1607,7 @@ nextslot: } /** - * Implementation of read() syscall. + * dvb_ca_en50221_io_read - Implementation of read() syscall. * * @file: File structure. * @buf: Destination buffer. @@ -1714,7 +1718,7 @@ exit: } /** - * Implementation of file open syscall. + * dvb_ca_en50221_io_open - Implementation of file open syscall. * * @inode: Inode concerned. * @file: File concerned. @@ -1764,7 +1768,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) } /** - * Implementation of file close syscall. + * dvb_ca_en50221_io_release - Implementation of file close syscall. * * @inode: Inode concerned. * @file: File concerned. @@ -1793,7 +1797,7 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) } /** - * Implementation of poll() syscall. + * dvb_ca_en50221_io_poll - Implementation of poll() syscall. * * @file: File concerned. * @wait: poll wait table. @@ -1855,7 +1859,7 @@ static const struct dvb_device dvbdev_ca = { /* Initialisation/shutdown functions */ /** - * Initialise a new DVB CA EN50221 interface device. + * dvb_ca_en50221_init - Initialise a new DVB CA EN50221 interface device. * * @dvb_adapter: DVB adapter to attach the new CA device to. * @pubca: The dvb_ca instance. @@ -1947,7 +1951,7 @@ exit: EXPORT_SYMBOL(dvb_ca_en50221_init); /** - * Release a DVB CA EN50221 interface device. + * dvb_ca_en50221_release - Release a DVB CA EN50221 interface device. * * @pubca: The associated dvb_ca instance. */ diff --git a/dvb-core/dvb_frontend.c b/dvb-core/dvb_frontend.c index 9f6ce4b..01193b3 100644 --- a/dvb-core/dvb_frontend.c +++ b/dvb-core/dvb_frontend.c @@ -20,6 +20,7 @@ #include #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) #include +#include #else #include #endif @@ -487,6 +488,10 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache, tmp; + if (fepriv->max_drift) + dev_warn(fe->dvb->device, + "Frontend requested software zigzag, but didn't set the frequency step size\n"); + /* if we've got no parameters, just keep idling */ if (fepriv->state & FESTATE_IDLE) { fepriv->delay = 3 * HZ; @@ -990,6 +995,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe) fe->ops.info.symbol_rate_max); return -EINVAL; } + break; default: break; } @@ -1065,108 +1071,100 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) return 0; } -#define _DTV_CMD(n, s, b) \ -[n] = { \ - .name = #n, \ - .cmd = n, \ - .set = s,\ - .buffer = b \ -} +#define _DTV_CMD(n) \ + [n] = #n -struct dtv_cmds_h { - char *name; /* A display name for debugging purposes */ - - __u32 cmd; /* A unique ID */ - - /* Flags */ - __u32 set:1; /* Either a set or get property */ - __u32 buffer:1; /* Does this property use the buffer? */ - __u32 reserved:30; /* Align */ -}; - -static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { - _DTV_CMD(DTV_TUNE, 1, 0), - _DTV_CMD(DTV_CLEAR, 1, 0), +static char *dtv_cmds[DTV_MAX_COMMAND + 1] = { + _DTV_CMD(DTV_TUNE), + _DTV_CMD(DTV_CLEAR), /* Set */ - _DTV_CMD(DTV_FREQUENCY, 1, 0), - _DTV_CMD(DTV_BANDWIDTH_HZ, 1, 0), - _DTV_CMD(DTV_MODULATION, 1, 0), - _DTV_CMD(DTV_INVERSION, 1, 0), - _DTV_CMD(DTV_DISEQC_MASTER, 1, 1), - _DTV_CMD(DTV_SYMBOL_RATE, 1, 0), - _DTV_CMD(DTV_INNER_FEC, 1, 0), - _DTV_CMD(DTV_VOLTAGE, 1, 0), - _DTV_CMD(DTV_TONE, 1, 0), - _DTV_CMD(DTV_PILOT, 1, 0), - _DTV_CMD(DTV_ROLLOFF, 1, 0), - _DTV_CMD(DTV_DELIVERY_SYSTEM, 1, 0), - _DTV_CMD(DTV_HIERARCHY, 1, 0), - _DTV_CMD(DTV_CODE_RATE_HP, 1, 0), - _DTV_CMD(DTV_CODE_RATE_LP, 1, 0), - _DTV_CMD(DTV_GUARD_INTERVAL, 1, 0), - _DTV_CMD(DTV_TRANSMISSION_MODE, 1, 0), - _DTV_CMD(DTV_INTERLEAVING, 1, 0), + _DTV_CMD(DTV_FREQUENCY), + _DTV_CMD(DTV_BANDWIDTH_HZ), + _DTV_CMD(DTV_MODULATION), + _DTV_CMD(DTV_INVERSION), + _DTV_CMD(DTV_DISEQC_MASTER), + _DTV_CMD(DTV_SYMBOL_RATE), + _DTV_CMD(DTV_INNER_FEC), + _DTV_CMD(DTV_VOLTAGE), + _DTV_CMD(DTV_TONE), + _DTV_CMD(DTV_PILOT), + _DTV_CMD(DTV_ROLLOFF), + _DTV_CMD(DTV_DELIVERY_SYSTEM), + _DTV_CMD(DTV_HIERARCHY), + _DTV_CMD(DTV_CODE_RATE_HP), + _DTV_CMD(DTV_CODE_RATE_LP), + _DTV_CMD(DTV_GUARD_INTERVAL), + _DTV_CMD(DTV_TRANSMISSION_MODE), + _DTV_CMD(DTV_INTERLEAVING), - _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION, 1, 0), - _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING, 1, 0), - _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID, 1, 0), - _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX, 1, 0), - _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYER_ENABLED, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_FEC, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_FEC, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_FEC, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 1, 0), - _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 1, 0), + _DTV_CMD(DTV_ISDBT_PARTIAL_RECEPTION), + _DTV_CMD(DTV_ISDBT_SOUND_BROADCASTING), + _DTV_CMD(DTV_ISDBT_SB_SUBCHANNEL_ID), + _DTV_CMD(DTV_ISDBT_SB_SEGMENT_IDX), + _DTV_CMD(DTV_ISDBT_SB_SEGMENT_COUNT), + _DTV_CMD(DTV_ISDBT_LAYER_ENABLED), + _DTV_CMD(DTV_ISDBT_LAYERA_FEC), + _DTV_CMD(DTV_ISDBT_LAYERA_MODULATION), + _DTV_CMD(DTV_ISDBT_LAYERA_SEGMENT_COUNT), + _DTV_CMD(DTV_ISDBT_LAYERA_TIME_INTERLEAVING), + _DTV_CMD(DTV_ISDBT_LAYERB_FEC), + _DTV_CMD(DTV_ISDBT_LAYERB_MODULATION), + _DTV_CMD(DTV_ISDBT_LAYERB_SEGMENT_COUNT), + _DTV_CMD(DTV_ISDBT_LAYERB_TIME_INTERLEAVING), + _DTV_CMD(DTV_ISDBT_LAYERC_FEC), + _DTV_CMD(DTV_ISDBT_LAYERC_MODULATION), + _DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT), + _DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING), - _DTV_CMD(DTV_STREAM_ID, 1, 0), - _DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY, 1, 0), - _DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX, 1, 0), - _DTV_CMD(DTV_LNA, 1, 0), - _DTV_CMD(DTV_INPUT, 1, 0), + _DTV_CMD(DTV_STREAM_ID), + _DTV_CMD(DTV_DVBT2_PLP_ID_LEGACY), + _DTV_CMD(DTV_SCRAMBLING_SEQUENCE_INDEX), + _DTV_CMD(DTV_LNA), + _DTV_CMD(DTV_INPUT), /* Get */ - _DTV_CMD(DTV_DISEQC_SLAVE_REPLY, 0, 1), - _DTV_CMD(DTV_API_VERSION, 0, 0), + _DTV_CMD(DTV_DISEQC_SLAVE_REPLY), + _DTV_CMD(DTV_API_VERSION), - _DTV_CMD(DTV_ENUM_DELSYS, 0, 0), + _DTV_CMD(DTV_ENUM_DELSYS), - _DTV_CMD(DTV_ATSCMH_PARADE_ID, 1, 0), - _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE, 1, 0), + _DTV_CMD(DTV_ATSCMH_PARADE_ID), + _DTV_CMD(DTV_ATSCMH_RS_FRAME_ENSEMBLE), - _DTV_CMD(DTV_ATSCMH_FIC_VER, 0, 0), - _DTV_CMD(DTV_ATSCMH_NOG, 0, 0), - _DTV_CMD(DTV_ATSCMH_TNOG, 0, 0), - _DTV_CMD(DTV_ATSCMH_SGN, 0, 0), - _DTV_CMD(DTV_ATSCMH_PRC, 0, 0), - _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE, 0, 0), - _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI, 0, 0), - _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC, 0, 0), - _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE, 0, 0), - _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A, 0, 0), - _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B, 0, 0), - _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C, 0, 0), - _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D, 0, 0), + _DTV_CMD(DTV_ATSCMH_FIC_VER), + _DTV_CMD(DTV_ATSCMH_NOG), + _DTV_CMD(DTV_ATSCMH_TNOG), + _DTV_CMD(DTV_ATSCMH_SGN), + _DTV_CMD(DTV_ATSCMH_PRC), + _DTV_CMD(DTV_ATSCMH_RS_FRAME_MODE), + _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_PRI), + _DTV_CMD(DTV_ATSCMH_RS_CODE_MODE_SEC), + _DTV_CMD(DTV_ATSCMH_SCCC_BLOCK_MODE), + _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_A), + _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_B), + _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_C), + _DTV_CMD(DTV_ATSCMH_SCCC_CODE_MODE_D), /* Statistics API */ - _DTV_CMD(DTV_STAT_SIGNAL_STRENGTH, 0, 0), - _DTV_CMD(DTV_STAT_CNR, 0, 0), - _DTV_CMD(DTV_STAT_PRE_ERROR_BIT_COUNT, 0, 0), - _DTV_CMD(DTV_STAT_PRE_TOTAL_BIT_COUNT, 0, 0), - _DTV_CMD(DTV_STAT_POST_ERROR_BIT_COUNT, 0, 0), - _DTV_CMD(DTV_STAT_POST_TOTAL_BIT_COUNT, 0, 0), - _DTV_CMD(DTV_STAT_ERROR_BLOCK_COUNT, 0, 0), - _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0), + _DTV_CMD(DTV_STAT_SIGNAL_STRENGTH), + _DTV_CMD(DTV_STAT_CNR), + _DTV_CMD(DTV_STAT_PRE_ERROR_BIT_COUNT), + _DTV_CMD(DTV_STAT_PRE_TOTAL_BIT_COUNT), + _DTV_CMD(DTV_STAT_POST_ERROR_BIT_COUNT), + _DTV_CMD(DTV_STAT_POST_TOTAL_BIT_COUNT), + _DTV_CMD(DTV_STAT_ERROR_BLOCK_COUNT), + _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT), }; +static char *dtv_cmd_name(u32 cmd) +{ +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18)) + cmd = array_index_nospec(cmd, DTV_MAX_COMMAND); +#endif + return dtv_cmds[cmd]; +} + /* Synchronise the legacy tuning parameters into the cache, so that demodulator * drivers can use a single set_frontend tuning function, regardless of whether * it's being used for the legacy or new API, reducing code and complexity. @@ -1349,8 +1347,9 @@ static int dtv_property_process_get(struct dvb_frontend *fe, struct file *file) { int ncaps; + unsigned int len = 1; - switch(tvp->cmd) { + switch (tvp->cmd) { case DTV_ENUM_DELSYS: ncaps = 0; while (ncaps < MAX_DELSYS && fe->ops.delsys[ncaps]) { @@ -1358,6 +1357,7 @@ static int dtv_property_process_get(struct dvb_frontend *fe, ncaps++; } tvp->u.buffer.len = ncaps; + len = ncaps; break; case DTV_FREQUENCY: tvp->u.data = c->frequency; @@ -1543,27 +1543,51 @@ static int dtv_property_process_get(struct dvb_frontend *fe, /* Fill quality measures */ case DTV_STAT_SIGNAL_STRENGTH: tvp->u.st = c->strength; + if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32)) + tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32); + len = tvp->u.buffer.len; break; case DTV_STAT_CNR: tvp->u.st = c->cnr; + if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32)) + tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32); + len = tvp->u.buffer.len; break; case DTV_STAT_PRE_ERROR_BIT_COUNT: tvp->u.st = c->pre_bit_error; + if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32)) + tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32); + len = tvp->u.buffer.len; break; case DTV_STAT_PRE_TOTAL_BIT_COUNT: tvp->u.st = c->pre_bit_count; + if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32)) + tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32); + len = tvp->u.buffer.len; break; case DTV_STAT_POST_ERROR_BIT_COUNT: tvp->u.st = c->post_bit_error; + if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32)) + tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32); + len = tvp->u.buffer.len; break; case DTV_STAT_POST_TOTAL_BIT_COUNT: tvp->u.st = c->post_bit_count; + if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32)) + tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32); + len = tvp->u.buffer.len; break; case DTV_STAT_ERROR_BLOCK_COUNT: tvp->u.st = c->block_error; + if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32)) + tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32); + len = tvp->u.buffer.len; break; case DTV_STAT_TOTAL_BLOCK_COUNT: tvp->u.st = c->block_count; + if (tvp->u.buffer.len > MAX_DTV_STATS * sizeof(u32)) + tvp->u.buffer.len = MAX_DTV_STATS * sizeof(u32); + len = tvp->u.buffer.len; break; default: dev_dbg(fe->dvb->device, @@ -1572,18 +1596,13 @@ static int dtv_property_process_get(struct dvb_frontend *fe, return -EINVAL; } - if (!dtv_cmds[tvp->cmd].buffer) - dev_dbg(fe->dvb->device, - "%s: GET cmd 0x%08x (%s) = 0x%08x\n", - __func__, tvp->cmd, dtv_cmds[tvp->cmd].name, - tvp->u.data); - else - dev_dbg(fe->dvb->device, - "%s: GET cmd 0x%08x (%s) len %d: %*ph\n", - __func__, - tvp->cmd, dtv_cmds[tvp->cmd].name, - tvp->u.buffer.len, - tvp->u.buffer.len, tvp->u.buffer.data); + if (len < 1) + len = 1; + + dev_dbg(fe->dvb->device, + "%s: GET cmd 0x%08x (%s) len %d: %*ph\n", + __func__, tvp->cmd, dtv_cmd_name(tvp->cmd), + tvp->u.buffer.len, tvp->u.buffer.len, tvp->u.buffer.data); return 0; } @@ -1806,6 +1825,53 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) return emulate_delivery_system(fe, delsys); } +static void prepare_tuning_algo_parameters(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dvb_frontend_tune_settings fetunesettings = { 0 }; + + /* get frontend-specific tuning settings */ + if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { + fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; + fepriv->max_drift = fetunesettings.max_drift; + fepriv->step_size = fetunesettings.step_size; + } else { + /* default values */ + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_ISDBS: + case SYS_TURBO: + case SYS_DVBC_ANNEX_A: + case SYS_DVBC_ANNEX_C: + fepriv->min_delay = HZ / 20; + fepriv->step_size = c->symbol_rate / 16000; + fepriv->max_drift = c->symbol_rate / 2000; + break; + case SYS_DVBT: + case SYS_DVBT2: + case SYS_ISDBT: + case SYS_DTMB: + fepriv->min_delay = HZ / 20; + fepriv->step_size = dvb_frontend_get_stepsize(fe) * 2; + fepriv->max_drift = fepriv->step_size + 1; + break; + default: + /* + * FIXME: This sounds wrong! if freqency_stepsize is + * defined by the frontend, why not use it??? + */ + fepriv->min_delay = HZ / 20; + fepriv->step_size = 0; /* no zigzag */ + fepriv->max_drift = 0; + break; + } + } + if (dvb_override_tune_delay > 0) + fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; +} + /** * dtv_property_process_set - Sets a single DTV property * @fe: Pointer to &struct dvb_frontend @@ -1834,7 +1900,7 @@ static int dtv_property_process_set(struct dvb_frontend *fe, else dev_dbg(fe->dvb->device, "%s: SET cmd 0x%08x (%s) to 0x%08x\n", - __func__, cmd, dtv_cmds[cmd].name, data); + __func__, cmd, dtv_cmd_name(cmd), data); switch (cmd) { case DTV_CLEAR: /* @@ -2204,7 +2270,6 @@ static int dtv_set_frontend(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - struct dvb_frontend_tune_settings fetunesettings; u32 rolloff = 0; if (dvb_frontend_check_parameters(fe) < 0) @@ -2282,46 +2347,7 @@ static int dtv_set_frontend(struct dvb_frontend *fe) if (c->hierarchy == HIERARCHY_NONE && c->code_rate_LP == FEC_NONE) c->code_rate_LP = FEC_AUTO; - /* get frontend-specific tuning settings */ - memset(&fetunesettings, 0, sizeof(struct dvb_frontend_tune_settings)); - if (fe->ops.get_tune_settings && (fe->ops.get_tune_settings(fe, &fetunesettings) == 0)) { - fepriv->min_delay = (fetunesettings.min_delay_ms * HZ) / 1000; - fepriv->max_drift = fetunesettings.max_drift; - fepriv->step_size = fetunesettings.step_size; - } else { - /* default values */ - switch (c->delivery_system) { - case SYS_DVBS: - case SYS_DVBS2: - case SYS_ISDBS: - case SYS_TURBO: - case SYS_DVBC_ANNEX_A: - case SYS_DVBC_ANNEX_C: - fepriv->min_delay = HZ / 20; - fepriv->step_size = c->symbol_rate / 16000; - fepriv->max_drift = c->symbol_rate / 2000; - break; - case SYS_DVBT: - case SYS_DVBT2: - case SYS_ISDBT: - case SYS_DTMB: - fepriv->min_delay = HZ / 20; - fepriv->step_size = dvb_frontend_get_stepsize(fe) * 2; - fepriv->max_drift = (dvb_frontend_get_stepsize(fe) * 2) + 1; - break; - default: - /* - * FIXME: This sounds wrong! if freqency_stepsize is - * defined by the frontend, why not use it??? - */ - fepriv->min_delay = HZ / 20; - fepriv->step_size = 0; /* no zigzag */ - fepriv->max_drift = 0; - break; - } - } - if (dvb_override_tune_delay > 0) - fepriv->min_delay = (dvb_override_tune_delay * HZ) / 1000; + prepare_tuning_algo_parameters(fe); fepriv->state = FESTATE_RETUNE; @@ -2336,7 +2362,6 @@ static int dtv_set_frontend(struct dvb_frontend *fe) return 0; } - static int dvb_get_property(struct dvb_frontend *fe, struct file *file, struct dtv_properties *tvps) { @@ -3028,13 +3053,13 @@ int dvb_register_frontend(struct dvb_adapter *dvb, fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; - dev_info(fe->dvb->device, - "DVB: registering adapter %i frontend %i (%s)...\n", - fe->dvb->num, fe->id, fe->ops.info.name); - dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template, fe, DVB_DEVICE_FRONTEND, 0); + dev_info(fe->dvb->device, + "DVB: registering adapter %i frontend %i (%s)...\n", + fe->dvb->num, fepriv->dvbdev->id, fe->ops.info.name); + /* * Initialize the cache to the proper values according with the * first supported delivery system (ops->delsys[0]) diff --git a/dvb-core/dvb_net.c b/dvb-core/dvb_net.c index 70a2a5b..05cc5c1 100644 --- a/dvb-core/dvb_net.c +++ b/dvb-core/dvb_net.c @@ -215,7 +215,7 @@ static int ule_exthdr_padding(struct dvb_net_priv *p) } /* - * Handle ULE extension headers. + * Handle ULE extension headers. * Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding. * Returns: >= 0: nr. of bytes consumed by next extension header * -1: Mandatory extension header that is not recognized or TEST SNDU; discard. @@ -553,7 +553,7 @@ static int dvb_net_ule_new_payload(struct dvb_net_ule_handle *h) h->priv->ule_sndu_type_1 = 1; h->ts_remain -= 1; h->from_where += 1; - /* fallthrough */ + fallthrough; case 0: h->new_ts = 1; h->ts += TS_SZ; @@ -1018,7 +1018,7 @@ static u8 mask_promisc[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; static int dvb_net_filter_sec_set(struct net_device *dev, struct dmx_section_filter **secfilter, - u8 *mac, u8 *mac_mask) + const u8 *mac, u8 *mac_mask) { struct dvb_net_priv *priv = netdev_priv(dev); int ret; @@ -1062,7 +1062,7 @@ static int dvb_net_feed_start(struct net_device *dev) int ret = 0, i; struct dvb_net_priv *priv = netdev_priv(dev); struct dmx_demux *demux = priv->demux; - unsigned char *mac = (unsigned char *) dev->dev_addr; + const unsigned char *mac = (unsigned char *) dev->dev_addr; netdev_dbg(dev, "rx_mode %i\n", priv->rx_mode); mutex_lock(&priv->mutex); @@ -1282,8 +1282,11 @@ static int dvb_net_set_mac (struct net_device *dev, void *p) struct dvb_net_priv *priv = netdev_priv(dev); struct sockaddr *addr=p; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0)) memcpy(dev->dev_addr, addr->sa_data, dev->addr_len); - +#else + eth_hw_addr_set(dev, addr->sa_data); +#endif if (netif_running(dev)) schedule_work(&priv->restart_net_feed_wq); @@ -1381,8 +1384,11 @@ static int dvb_net_add_if(struct dvb_net *dvbnet, u16 pid, u8 feedtype) dvbnet->dvbdev->adapter->num, if_num); net->addr_len = 6; +#if (LINUX_VERSION_CODE < KERNEL_VERSION(5, 17, 0)) memcpy(net->dev_addr, dvbnet->dvbdev->adapter->proposed_mac, 6); - +#else + eth_hw_addr_set(net, dvbnet->dvbdev->adapter->proposed_mac); +#endif dvbnet->device[if_num] = net; priv = netdev_priv(net); diff --git a/dvb-core/dvb_ringbuffer.c b/dvb-core/dvb_ringbuffer.c index 42f39af..60830ef 100644 --- a/dvb-core/dvb_ringbuffer.c +++ b/dvb-core/dvb_ringbuffer.c @@ -391,7 +391,9 @@ ssize_t dvb_ringbuffer_pkt_next(struct dvb_ringbuffer *rbuf, size_t idx, size_t* idx = (idx + curpktlen + DVB_RINGBUFFER_PKTHDRSIZE) % rbuf->size; } - consumed = (idx - rbuf->pread) % rbuf->size; + consumed = idx - rbuf->pread; + if (consumed < 0) + consumed += rbuf->size; while((dvb_ringbuffer_avail(rbuf) - consumed) > DVB_RINGBUFFER_PKTHDRSIZE) { diff --git a/dvb-core/dvbdev.c b/dvb-core/dvbdev.c index 6a991a6..e26fee3 100644 --- a/dvb-core/dvbdev.c +++ b/dvb-core/dvbdev.c @@ -79,13 +79,17 @@ static const char * const dnames[] = { static const u8 minor_type[] = { [DVB_DEVICE_VIDEO] = 0, [DVB_DEVICE_AUDIO] = 1, - [DVB_DEVICE_SEC] = 2, + [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, + [DVB_DEVICE_CI] = 9, + [DVB_DEVICE_MOD] = 10, + [DVB_DEVICE_NS] = 11, + [DVB_DEVICE_NSD] = 12, }; #define nums2minor(num, type, id) \ @@ -248,6 +252,7 @@ static void dvb_media_device_free(struct dvb_device *dvbdev) if (dvbdev->adapter->conn) { media_device_unregister_entity(dvbdev->adapter->conn); + kfree(dvbdev->adapter->conn); dvbdev->adapter->conn = NULL; kfree(dvbdev->adapter->conn_pads); dvbdev->adapter->conn_pads = NULL; @@ -346,7 +351,7 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev, if (npads) { dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads), GFP_KERNEL); - if (!dvbdev->pads){ + if (!dvbdev->pads) { kfree(dvbdev->entity); return -ENOMEM; } @@ -512,6 +517,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, break; if (minor == MAX_DVB_MINORS) { + list_del (&dvbdev->list_head); kfree(dvbdevfops); kfree(dvbdev); up_write(&minor_rwsem); @@ -532,6 +538,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, __func__); dvb_media_device_free(dvbdev); + list_del (&dvbdev->list_head); kfree(dvbdevfops); kfree(dvbdev); mutex_unlock(&dvbdev_register_lock); @@ -546,6 +553,10 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, if (IS_ERR(clsdev)) { pr_err("%s: failed to create device dvb%d.%s%d (%ld)\n", __func__, adap->num, dnames[type], id, PTR_ERR(clsdev)); + dvb_media_device_free(dvbdev); + list_del (&dvbdev->list_head); + kfree(dvbdevfops); + kfree(dvbdev); return PTR_ERR(clsdev); } dprintk("DVB: register adapter%d/%s%d @ minor: %i (0x%02x)\n", @@ -687,7 +698,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap, ret = media_device_register_entity(mdev, conn); if (ret) return ret; - + if (!ntuner) { ret = media_create_pad_links(mdev, MEDIA_ENT_F_CONN_RF, @@ -987,7 +998,7 @@ struct i2c_client *dvb_module_probe(const char *module_name, unsigned char addr, void *platform_data) { - struct i2c_client *client; + struct i2c_client *client; struct i2c_board_info *board_info; board_info = kzalloc(sizeof(*board_info), GFP_KERNEL); diff --git a/frontends/Makefile.kernel b/frontends/Makefile.kernel index 860129b..7757ac9 100644 --- a/frontends/Makefile.kernel +++ b/frontends/Makefile.kernel @@ -4,6 +4,7 @@ ccflags-y += -I$(srctree)/drivers/media/dvb-core/ ccflags-y += -I$(srctree)/drivers/media/tuners/ +ccflags-y += --include=dd_compat.h # FIXME: RTL2832 SDR driver uses power management directly from USB IF driver ifdef CONFIG_DVB_RTL2832_SDR diff --git a/frontends/cxd2843.c b/frontends/cxd2843.c index d6f0646..b2ce30f 100644 --- a/frontends/cxd2843.c +++ b/frontends/cxd2843.c @@ -54,6 +54,7 @@ struct cxd_state { struct dvb_frontend frontend; struct i2c_adapter *i2c; struct mutex mutex; + int repi2cerr; u8 adrt; u8 curbankt; @@ -91,12 +92,13 @@ struct cxd_state { u8 is24MHz; }; -static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) +static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len, int flag) { struct i2c_msg msg = { .addr = adr, .flags = 0, .buf = data, .len = len}; if (i2c_transfer(adap, &msg, 1) != 1) { - pr_err("cxd2843: i2c_write error adr %02x data %02x\n", adr, data[0]); + if (flag) + pr_err("cxd2843: i2c_write error adr %02x data %02x\n", adr, data[0]); return -1; } return 0; @@ -113,14 +115,14 @@ static int writeregs(struct cxd_state *state, u8 adr, u8 reg, } data[0] = reg; memcpy(data + 1, regd, len); - return i2c_write(state->i2c, adr, data, len + 1); + return i2c_write(state->i2c, adr, data, len + 1, state->repi2cerr); } static int writereg(struct cxd_state *state, u8 adr, u8 reg, u8 dat) { u8 mm[2] = {reg, dat}; - return i2c_write(state->i2c, adr, mm, 2); + return i2c_write(state->i2c, adr, mm, 2, state->repi2cerr); } static int i2c_read(struct i2c_adapter *adap, @@ -130,17 +132,19 @@ static int i2c_read(struct i2c_adapter *adap, .buf = msg, .len = len}, { .addr = adr, .flags = I2C_M_RD, .buf = answ, .len = alen } }; - if (i2c_transfer(adap, msgs, 2) != 2) { - pr_err("cxd2843: i2c_read error\n"); + if (i2c_transfer(adap, msgs, 2) != 2) return -1; - } return 0; } static int readregs(struct cxd_state *state, u8 adr, u8 reg, u8 *val, int count) { - return i2c_read(state->i2c, adr, ®, 1, val, count); + int ret = i2c_read(state->i2c, adr, ®, 1, val, count); + + if (ret && state->repi2cerr) + pr_err("cxd2843: i2c_read error\n"); + return ret; } static int readregst_unlocked(struct cxd_state *cxd, u8 bank, @@ -1644,7 +1648,7 @@ static void init_state(struct cxd_state *state, struct cxd2843_cfg *cfg) /* IF Fullscale 0x50 = 1.4V, 0x39 = 1V, 0x28 = 0.7V */ state->IF_FS = 0x50; state->is24MHz = (cfg->osc == 24000000) ? 1 : 0; - printk("is24Mhz = %u\n", state->is24MHz); + printk("is24Mhz = %u, adr = %02x\n", state->is24MHz, cfg->adr); } static int get_tune_settings(struct dvb_frontend *fe, @@ -2646,8 +2650,9 @@ static int probe(struct cxd_state *state) status = readregsx(state, 0x00, 0xFD, &ChipID, 1); if (status) return status; - - printk("ChipID = %02X\n", ChipID); + + state->repi2cerr = 1; + //pr_info("cxd2843: ChipID = %02X\n", ChipID); switch (ChipID) { case 0xa4: state->type = CXD2843; @@ -2682,7 +2687,6 @@ struct dvb_frontend *cxd2843_attach(struct i2c_adapter *i2c, { struct cxd_state *state = NULL; - pr_info("attach\n"); state = kzalloc(sizeof(struct cxd_state), GFP_KERNEL); if (!state) return NULL; diff --git a/frontends/drxk_hard.c b/frontends/drxk_hard.c index 456e382..a6553d4 100644 --- a/frontends/drxk_hard.c +++ b/frontends/drxk_hard.c @@ -1566,7 +1566,7 @@ static int SetOperationMode(struct drxk_state *state, enum OperationMode oMode) case OM_QAM_ITU_B: status = -1; break; - case OM_QAM_ITU_A: /* fallthrough */ + case OM_QAM_ITU_A: case OM_QAM_ITU_C: CHK_ERROR(MPEGTSStop(state)); CHK_ERROR(PowerDownQAM(state)); @@ -1589,7 +1589,7 @@ static int SetOperationMode(struct drxk_state *state, enum OperationMode oMode) case OM_QAM_ITU_B: status = -1; break; - case OM_QAM_ITU_A: /* fallthrough */ + case OM_QAM_ITU_A: case OM_QAM_ITU_C: state->m_OperationMode = oMode; CHK_ERROR(SetQAMStandard(state,oMode)); @@ -1765,7 +1765,7 @@ static int MPEGTSDtoSetup(struct drxk_state *state, enum OperationMode oMode) fecOcRcnCtlRate = 0xC00000; staticCLK = state->m_DVBTStaticCLK; break; - case OM_QAM_ITU_A: /* fallthrough */ + case OM_QAM_ITU_A: case OM_QAM_ITU_C: fecOcTmdMode = 0x0004; fecOcRcnCtlRate = 0xD2B4EE; /* good for >63 Mb/s */ @@ -2804,12 +2804,12 @@ static int DVBTScCommand(struct drxk_state *state, case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM: status = Write16_0(state, OFDM_SC_RA_RAM_PARAM1__A, param1); /* All commands using 1 parameters */ - /* fall through */ + fallthrough; case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING: case OFDM_SC_RA_RAM_CMD_USER_IO: status = Write16_0(state, OFDM_SC_RA_RAM_PARAM0__A, param0); /* All commands using 0 parameters */ - /* fall through */ + fallthrough; case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM: case OFDM_SC_RA_RAM_CMD_NULL: /* Write command */ @@ -3218,7 +3218,7 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M; /* try first guess DRX_FFTMODE_8K */ - /* fall through */ + fallthrough; case TRANSMISSION_MODE_8K: transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K; break; @@ -3237,7 +3237,7 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF case GUARD_INTERVAL_AUTO: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M; /* try first guess DRX_GUARD_1DIV4 */ - /* fall through */ + fallthrough; case GUARD_INTERVAL_1_4: transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4; break; @@ -3265,7 +3265,7 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF /* try first guess SC_RA_RAM_OP_PARAM_HIER_NO */ // transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; //break; - /* fall through */ + fallthrough; case HIERARCHY_1: transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1; break; @@ -3288,7 +3288,7 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M; /* try first guess DRX_CONSTELLATION_QAM64 */ - /* fall through */ + fallthrough; case QAM_64: transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64; break; @@ -3311,8 +3311,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_PRIO_HI; WR16(devAddr, OFDM_EC_SB_PRIOR__A, OFDM_EC_SB_PRIOR_HI)); break; - case DRX_PRIORITY_UNKNOWN : /* fall through */ - default: + case DRX_PRIORITY_UNKNOWN: + default: return (DRX_STS_INVALID_ARG); break; } @@ -3332,7 +3332,7 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M; /* try first guess DRX_CODERATE_2DIV3 */ - /* fall through */ + fallthrough; case FEC_2_3 : transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3; break; diff --git a/frontends/mxl5xx.c b/frontends/mxl5xx.c index 6f7308b..ef5e9ac 100644 --- a/frontends/mxl5xx.c +++ b/frontends/mxl5xx.c @@ -786,7 +786,7 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties default: break; } - /* fallthrough */ + fallthrough; case SYS_DVBS: switch ((MXL_HYDRA_MODULATION_E) regData[DMD_MODULATION_SCHEME_ADDR]) { @@ -825,13 +825,15 @@ static int set_input(struct dvb_frontend *fe, int input) struct mxl *state = fe->demodulator_priv; struct dtv_frontend_properties *p = &fe->dtv_property_cache; - state->tuner = p->input = input; + state->tuner = input; +#ifndef KERNEL_DVB_CORE + p->input = input; +#endif return 0; } static struct dvb_frontend_ops mxl_ops = { .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, - .xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */ .info = { .name = "MXL5XX", .frequency_min_hz = 300000000, @@ -856,7 +858,10 @@ static struct dvb_frontend_ops mxl_ops = { .read_signal_strength = read_signal_strength, .read_ucblocks = read_ucblocks, .get_frontend = get_frontend, +#ifndef KERNEL_DVB_CORE .set_input = set_input, + .xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */ +#endif .diseqc_send_master_cmd = send_master_cmd, }; @@ -1873,7 +1878,8 @@ static int probe(struct mxl *state, struct mxl5xx_cfg *cfg) struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c, struct mxl5xx_cfg *cfg, - u32 demod, u32 tuner) + u32 demod, u32 tuner, + int (**fn_set_input)(struct dvb_frontend *, int)) { struct mxl *state; struct mxl_base *base; @@ -1913,9 +1919,12 @@ struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c, list_add(&base->mxllist, &mxllist); } state->fe.ops = mxl_ops; +#ifndef KERNEL_DVB_CORE state->fe.ops.xbar[1] = demod; - state->fe.demodulator_priv = state; state->fe.dtv_property_cache.input = tuner; +#endif + state->fe.demodulator_priv = state; + *fn_set_input = set_input; list_add(&state->mxl, &base->mxls); return &state->fe; diff --git a/frontends/mxl5xx.h b/frontends/mxl5xx.h index 24ac1fa..1a3f5e7 100644 --- a/frontends/mxl5xx.h +++ b/frontends/mxl5xx.h @@ -23,12 +23,15 @@ struct mxl5xx_cfg { extern struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c, struct mxl5xx_cfg *cfg, - u32 demod, u32 tuner); + u32 demod, u32 tuner, + int (**fn_set_input)(struct dvb_frontend *, int)); + #else static inline struct dvb_frontend *mxl5xx_attach(struct i2c_adapter *i2c, struct mxl5xx_cfg *cfg, - u32 demod, u32 tuner) + u32 demod, u32 tuner, + int (**fn_set_input)(struct dvb_frontend *, int)) { pr_warn("%s: driver disabled by Kconfig\n", __func__); return NULL; diff --git a/frontends/stv0910.c b/frontends/stv0910.c index b289ef7..431028d 100644 --- a/frontends/stv0910.c +++ b/frontends/stv0910.c @@ -208,17 +208,35 @@ static int write_field(struct stv *state, u32 field, u8 val) return write_reg(state, field >> 16, new); } +static int read_field(struct stv *state, u32 field, u8 *val) +{ + int status; + u8 shift, mask; + + status = read_reg(state, field >> 16, val); + if (status) + return status; + mask = field & 0xff; + shift = (field >> 12) & 0xf; + *val = (*val & mask) >> shift; + return status; +} + #define set_field(_reg, _val) \ write_field(state, state->nr ? FSTV0910_P2_##_reg : \ FSTV0910_P1_##_reg, _val) +#define get_field(_reg, _val) \ + read_field(state, state->nr ? FSTV0910_P2_##_reg : \ + FSTV0910_P1_##_reg, _val) + #define set_reg(_reg, _val) \ write_reg(state, state->nr ? RSTV0910_P2_##_reg : \ RSTV0910_P1_##_reg, _val) #define get_reg(_reg, _val) \ read_reg(state, state->nr ? RSTV0910_P2_##_reg : \ - RTV0910_P1_##_reg, _val) + RSTV0910_P1_##_reg, _val) static const struct slookup s1_sn_lookup[] = { { 0, 9242 }, /* C/N= 0dB */ @@ -1112,8 +1130,9 @@ static int init_diseqc(struct stv *state) u16 offs = state->nr ? 0x40 : 0; /* Address offset */ u8 freq = ((state->base->mclk + 11000 * 32) / (22000 * 32)); - /* Disable receiver */ - write_reg(state, RSTV0910_P1_DISRXCFG + offs, 0x00); + write_reg(state, RSTV0910_P1_DISRXCFG + offs, 0x05); + //write_reg(state, RSTV0910_P1_DISRXF220 + offs, 0x69); 2b? + write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0xBA); /* Reset = 1 */ write_reg(state, RSTV0910_P1_DISTXCFG + offs, 0x3A); /* Reset = 0 */ write_reg(state, RSTV0910_P1_DISTXF22 + offs, freq); @@ -1617,12 +1636,28 @@ static int wait_dis(struct stv *state, u8 flag, u8 val) return -1; } +static int clear_slave(struct dvb_frontend *fe) +{ + struct stv *state = fe->demodulator_priv; + u8 n, d, done; + + get_field(RXEND, &done); + get_reg(DISRXBYTES, &n); + printk("clear: done = %u, %u fifo bytes\n", done, n); + + for (get_reg(DISRXBYTES, &n); n; n--) + get_reg(DISRXFIFO, &d); + return 0; +} + static int send_master_cmd(struct dvb_frontend *fe, struct dvb_diseqc_master_cmd *cmd) { struct stv *state = fe->demodulator_priv; int i; + clear_slave(fe); + set_field(DISRX_ON, 0); set_reg(DISTXCFG, 0x3e); for (i = 0; i < cmd->msg_len; i++) { wait_dis(state, 0x40, 0x00); @@ -1630,12 +1665,59 @@ static int send_master_cmd(struct dvb_frontend *fe, } set_reg(DISTXCFG, 0x3a); wait_dis(state, 0x20, 0x20); + set_field(DISRX_ON, 1); return 0; } static int recv_slave_reply(struct dvb_frontend *fe, struct dvb_diseqc_slave_reply *reply) { + struct stv *state = fe->demodulator_priv; + int i, to, flag = 0, max = sizeof(reply->msg); + u8 done, val, n = 0; + + +#if 0 + get_reg(DISRXBYTES, &val); + get_field(RXEND, &done); + printk("slave: done = %u, %u fifo bytes\n", done, val); +#endif + to = reply->timeout; + if (to < 0) { + to = 100; + flag = 1; + } else if (to > 5000) + to = 100; + reply->msg_len = 0; + for (i = 0; i < to; i += 10) { + get_reg(DISRXBYTES, &val); + if (flag && val) + break; + get_field(RXEND, &done); + if (val >= max || done) + break; + msleep(10); + } + get_reg(DISRXBYTES, &val); + printk("done = %u, %u fifo bytes, i=%u\n", done, val, i); + if (i == to && !val) + return -EIO; + if (done && !val) + return -EIO; + for (i = 100; i; i--) { + get_field(RXEND, &done); + + for (get_reg(DISRXBYTES, &n); n; n--) { + if (reply->msg_len == max) + return 0; + get_reg(DISRXFIFO, &reply->msg[reply->msg_len++]); + } + if (!n || done) + break; + msleep(10); + } + if (!i) + return -EIO; return 0; } diff --git a/frontends/tda18212dd.c b/frontends/tda18212dd.c index cf43a22..1235437 100644 --- a/frontends/tda18212dd.c +++ b/frontends/tda18212dd.c @@ -447,18 +447,13 @@ static int attach_init(struct tda_state *state) if (!state->m_isMaster) state->m_bLTEnable = false; - /*pr_info("tda18212dd: ChipID %04x %s\n", state->m_ID, - state->m_isMaster ? "master" : "slave");*/ - if (state->m_ID != 18212) return -1; stat = read_reg(state, POWER_STATE_1 , &PowerState); if (stat < 0) return stat; - - /*pr_info("tda18212dd: PowerState %02x\n", PowerState);*/ - + if (state->m_isMaster) { if (PowerState & 0x02) { /* msleep for XTAL Calibration @@ -539,7 +534,6 @@ static int PowerMeasurement(struct tda_state *state, u8 *pPowerLevel) if (*pPowerLevel > 110) *pPowerLevel = 110; } while (0); - /* pr_info("PL %d\n", *pPowerLevel); */ return status; } @@ -806,7 +800,6 @@ static int set_params(struct dvb_frontend *fe) bw = (p->bandwidth_hz + 999999) / 1000000; state->m_Frequency = p->frequency; - /*pr_info("tuner bw=%u freq=%u\n", bw, state->m_Frequency);*/ if (p->delivery_system == SYS_DVBT || p->delivery_system == SYS_DVBT2 || p->delivery_system == SYS_ISDBT || diff --git a/include/dd_compat.h b/include/dd_compat.h new file mode 100644 index 0000000..d1f019d --- /dev/null +++ b/include/dd_compat.h @@ -0,0 +1,39 @@ +#include + +#if (KERNEL_VERSION(3, 8, 0) <= LINUX_VERSION_CODE) +#define __devexit +#define __devinit +#define __devinitconst +#endif + +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef fallthrough +#if __has_attribute(__fallthrough__) +# define fallthrough __attribute__((__fallthrough__)) +#else +# define fallthrough do {} while (0) /* fallthrough */ +#endif +#endif + + +#ifdef KERNEL_DVB_CORE +#define DVB_DEVICE_CI 0 +#define DVB_DEVICE_MOD 6 +#define DVB_DEVICE_NS 7 +#define DVB_DEVICE_NSD 8 + +#define SYS_DVBC2 19 +#define ROLLOFF_15 4 +#define ROLLOFF_10 5 +#define ROLLOFF_5 6 + +#define FEC_1_4 13 +#define FEC_1_3 14 + +#define APSK_64 14 +#define APSK_128 15 +#define APSK_256 16 +#endif diff --git a/include/linux/dvb/mod.h b/include/linux/dvb/mod.h index 196c481..11c0470 100644 --- a/include/linux/dvb/mod.h +++ b/include/linux/dvb/mod.h @@ -44,8 +44,10 @@ enum mod_output_rate { SYS_ISDBT_6 = 16, SYS_J83B_64_6 = 24, SYS_J83B_256_6 = 25, - SYS_DVBS2_22 = 32, - SYS_DVBS2_24 = 33, + SYS_DVB_22 = 32, + SYS_DVB_24 = 33, + SYS_DVB_30 = 34, + SYS_ISDBS_2886 = 48, }; diff --git a/include/linux/media/dvbdev.h b/include/linux/media/dvbdev.h index c4005df..26770cd 100644 --- a/include/linux/media/dvbdev.h +++ b/include/linux/media/dvbdev.h @@ -27,11 +27,15 @@ #define DVB_MAJOR 212 +#if 0 #if defined(CONFIG_DVB_MAX_ADAPTERS) && CONFIG_DVB_MAX_ADAPTERS > 0 #define DVB_MAX_ADAPTERS CONFIG_DVB_MAX_ADAPTERS #else #define DVB_MAX_ADAPTERS 64 #endif +#endif + + #define DVB_MAX_ADAPTERS 64 #define DVB_UNSET (-1) @@ -326,7 +330,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap, int dvb_generic_open(struct inode *inode, struct file *file); /** - * dvb_generic_close - Digital TV close function, used by DVB devices + * dvb_generic_release - Digital TV close function, used by DVB devices * * @inode: pointer to &struct inode. * @file: pointer to &struct file. @@ -421,11 +425,12 @@ void dvb_module_release(struct i2c_client *client); /* Legacy generic DVB attach function. */ #ifdef CONFIG_MEDIA_ATTACH + /** * dvb_attach - attaches a DVB frontend into the DVB core. * * @FUNCTION: function on a frontend module to be called. - * @ARGS...: @FUNCTION arguments. + * @ARGS: @FUNCTION arguments. * * This ancillary function loads a frontend module in runtime and runs * the @FUNCTION function there, with @ARGS. diff --git a/lib/README.md b/lib/README.md new file mode 100644 index 0000000..f764fc5 --- /dev/null +++ b/lib/README.md @@ -0,0 +1,49 @@ +# LIBDDDVB +The libdddvb provides a userspace library to simplify tuning and +CI use. It detects DVB cards and their capabilities and selects +free frontends depending on a given delivery system. + + +In order to install the libdddvb library you need the dvben50221. + +On an Ubuntu and other Debian based system you can install it like this: + +`sudo apt-get install dvb-apps` + +After that you can build the libdddvb: + +`git clone https://github.com/DigitalDevices/dddvb.git` + +`cd dddvb/lib/; make` + +`sudo make install` + +If your distribution does not include a dvb-apps package, you can follow the +instructions at + +https://www.linuxtv.org/wiki/index.php/LinuxTV_dvb-apps + +on how to build it yourself. + + +# DDZAP + +You can now use the example program ddzap to see how the library +is used or to test your cards. + +A typical usage example would be the tuning of a +sattelite channel with a given LNB configuration. + +`ddzap -d S2 -p h -f 11494000 -s 22000000 -c ~/dddvb/lib/config/` + +where you would use the example configuration file for a unicable LNB +given in the sources. If you leave out the `-c` option a standard universal +LNB is assumed to be connected. + +Additionally you can use ddzap to open the /dev/dvb/adaptorX/dvrY device +that corresponds to the tuner that was automatically selected by the library +and pipe it to a media player, e.g. + + +`ddzap -d S2 -p h -f 11494000 -s 22000000 -c /home/dmocm/ddzapconf/ -o|vlc -` + diff --git a/lib/config/dddvb.conf b/lib/config/dddvb.conf index 3352c81..cb27303 100644 --- a/lib/config/dddvb.conf +++ b/lib/config/dddvb.conf @@ -17,3 +17,7 @@ Tuner5=5,984 Tuner6=6,1020 Tuner7=7,1056 Tuner8=8,1092 +Tuner9=1,1210 +Tuner10=2,1420 +Tuner11=3,1680 +Tuner12=4,2040 diff --git a/lib/config/dddvb.conf.example b/lib/config/dddvb.conf.example new file mode 100644 index 0000000..28a0840 --- /dev/null +++ b/lib/config/dddvb.conf.example @@ -0,0 +1,36 @@ +[scif] +# SCIF Settings +# Manufacturer = nn : Index to selected manaufacturer (only used in config webpage) +# Unit = nn : Index to selected unit (only used in config webpage) +# Type = nn : Type of unit: 1: EN 50494, 2: TS 50607 +# TunerN = Slot,Frequency[,Pin] Slot = 1..nn, Frequency = 950..2150, Pin = 0-255 +# Slot = 0 (no SCIF) +# Slot = 1..8 for EN 50494, 1..32 for TS 50607 +Type=0 +Tuner1=0 +Tuner2=0 +Tuner3=0 +Tuner4=0 +Tuner5=0 +Tuner6=0 +Tuner7=0 +Tuner8=0 +[LNB] +# +# LNB 1 Setting +# +Tuner=1 +Source=1 +LOF1=9750 +LOF2=10600 +LOFS=11700 + +[LNB] +# +# LNB 2 Setting +# +Tuner=2 +Source=1 +LOF1=9750 +LOF2=10600 +LOFS=11700 diff --git a/lib/config/dddvb.conf.example_uni b/lib/config/dddvb.conf.example_uni new file mode 100644 index 0000000..6853526 --- /dev/null +++ b/lib/config/dddvb.conf.example_uni @@ -0,0 +1,37 @@ +[CA] +family=unix +[scif] +# SCIF Settings +# Manufacturer = nn : Index to selected manaufacturer (only used in config webpage) +# Unit = nn : Index to selected unit (only used in config webpage) +# Type = nn : Type of unit: 1: EN 50494, 2: TS 50607 +# TunerN = Slot,Frequency[,Pin] Slot = 1..nn, Frequency = 950..2150, Pin = 0-255 +# Slot = 0 (no SCIF) +# Slot = 1..8 for EN 50494, 1..32 for TS 50607 +Manufacturer=0 +Unit=8 +Type=2 +Tuner1=1,1210 +Tuner2=2,1420 +Tuner3=3,1680 +Tuner4=4,2040 +Tuner5=5,984 +Tuner6=6,1020 +Tuner7=7,1056 +Tuner8=8,1092 +Tuner9=9,1128 +Tuner10=10,1164 +Tuner11=11,1256 +Tuner12=12,1292 +Tuner13=13,1328 +Tuner14=14,1364 +Tuner15=15,1458 +Tuner16=16,1494 +Tuner17=17,1530 +Tuner18=18,1566 +Tuner19=19,1602 +Tuner20=20,1638 +Tuner21=21,1716 +Tuner22=22,1752 +Tuner23=23,1788 +Tuner24=24,1824 \ No newline at end of file diff --git a/lib/ddzap.c b/lib/ddzap.c index cf29a41..1d5b303 100644 --- a/lib/ddzap.c +++ b/lib/ddzap.c @@ -12,6 +12,7 @@ #include #include #include +#include char line_start[16] = ""; char line_end[16] = "\r"; @@ -203,7 +204,7 @@ void proc_ts(int i, uint8_t *buf) if (ccin & 0x10) { if ( cc[pid]) { // TODO: 1 repetition allowed - if( ( ccin & 0x10 ) != 0 && (((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) ) + if ((((cc[pid] + 1) & 0x0F) != (ccin & 0x0F))) cc_errors += 1; } cc[pid] = ccin; @@ -271,7 +272,7 @@ int main(int argc, char **argv) struct dddvb_fe *fe; struct dddvb_params p; 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 = DDDVB_UNDEF; uint32_t mtype= DDDVB_UNDEF; uint32_t verbosity = 0; uint32_t get_ts = 1; @@ -308,20 +309,22 @@ int main(int argc, char **argv) {"tscheck", no_argument, 0, 't'}, {"tscheck_l", required_argument, 0, 'a'}, {"nodvr", no_argument , 0, 'q'}, - {"pam", no_argument , 0, 'a'}, + {"pam", no_argument , 0, 'P'}, + {"pam_color", no_argument , 0, 'e'}, {"help", no_argument , 0, 'h'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, - "e:c:i:f:s:d:p:hg:r:n:b:l:v:m:ota:q", + "e:c:i:f:s:d:p:hg:r:n:b:l:v:m:ota:qP", long_options, &option_index); if (c==-1) break; switch (c) { case 'e': - odvr = 2; color = strtoul(optarg, NULL, 0); + case 'P': + odvr = 2; break; case 'o': fout = stderr; @@ -341,7 +344,7 @@ int main(int argc, char **argv) break; } fprintf(fout,"performing continuity check\n"); - odvr = 2; + odvr = 3; break; case 'c': config = strdup(optarg); @@ -414,6 +417,8 @@ int main(int argc, char **argv) delsys = SYS_ISDBC; if (!strcmp(optarg, "ISDBT")) delsys = SYS_ISDBT; + if (!strcmp(optarg, "ISDBS")) + delsys = SYS_ISDBS; break; case 'p': if (!strcmp(optarg, "h") || !strcmp(optarg, "H")) @@ -425,12 +430,18 @@ int main(int argc, char **argv) get_ts = 0; break; 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]\n" + " [-f frequency(Hz for terr./kHz for SAT)]\n" + " [-m 16APSK/32APSK/64APSK/128APSK/256APSK]\n" + " (only needed for higher modulations than 8PSK) on some cards\n" " [-b bandwidth(Hz)] [-s symbol_rate(Hz)]\n" " [-g gold_code] [-r root_code] [-i id] [-n device_num]\n" " [-o (write dvr to stdout)]\n" " [-l (tuner source for unicable)]\n" - " [-t [display line](continuity check)]\n" + " [-t (continuity check)]\n" + " [-a [display line] (display continuity check in line)]\n" + " [-P (output IQ diagram as pam)]\n" + " [-e [color] (use color for pam 0=green)]\n" "\n" " delivery_system = C,S,S2,T,T2,J83B,ISDBC,ISDBT\n" " polarity = h/H,v/V\n" @@ -501,8 +512,10 @@ int main(int argc, char **argv) str = dddvb_get_strength(fe); cnr = dddvb_get_cnr(fe); - printf("stat=%02x, str=%lld.%03llddB, snr=%lld.%03llddB \n", - stat, (long long int)str/1000,(long long int) abs(str%1000),(long long int) cnr/1000, (long long int)abs(cnr%1000)); + printf("stat=%02x, str=%" PRId64 ".%03u dBm, " + "snr=%" PRId64 ".%03u dB\n", + stat, str/1000, abs(str%1000), + cnr/1000, abs(cnr%1000)); sleep(1); } } else { @@ -521,7 +534,8 @@ int main(int argc, char **argv) cnr = dddvb_get_cnr(fe); fprintf(stderr,"stat=%02x, str=%lld.%03llddB, snr=%lld.%03llddB \n", - stat,(long long int) str/1000,(long long int) abs(str%1000),(long long int) cnr/1000, (long long int)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); } fprintf(stderr,"got lock on %s\n", fe->name); @@ -531,29 +545,28 @@ int main(int argc, char **argv) if ((fd = open(filename ,O_RDONLY)) < 0){ fprintf(stderr,"Error opening input file:%s\n",filename); } - if (odvr > 0){ - switch (odvr){ - 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; + switch (odvr){ + case 1: + while(1){ + read(fd,buf,BUFFSIZE); + write(fileno(stdout),buf,BUFFSIZE); } - } else { + 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; + case 3: 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); + break; } } } diff --git a/lib/src/ca.c b/lib/src/ca.c index 6460758..9c38caa 100644 --- a/lib/src/ca.c +++ b/lib/src/ca.c @@ -14,9 +14,11 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -66,6 +68,32 @@ int streamsock(const char *port, int family, struct sockaddr *sadr) return sock; } +int unixsock(const char *path) +{ + unlink(path); + + struct sockaddr_un sa; + size_t hlen = offsetof(struct sockaddr_un, sun_path); + size_t pathlen = strlen(path); + if (pathlen > sizeof(sa.sun_path)) + return(-1); + memset(&sa, 0, hlen); + sa.sun_family = AF_UNIX; + if (pathlen > 0) + memcpy(sa.sun_path, path, pathlen); + + int sock = socket(AF_UNIX, SOCK_STREAM, 0); + if (sock == -1) + return(-1); + + if (bind(sock, (struct sockaddr *) &sa, (socklen_t) (hlen + pathlen)) == -1) { + close(sock); + return(-1); + } + + return(sock); +} + static int ai_callback(void *arg, uint8_t slot_id, uint16_t session_number, uint8_t application_type, uint16_t application_manufacturer, uint16_t manufacturer_code, uint8_t menu_string_length, @@ -357,10 +385,17 @@ static void handle_ci(struct dddvb_ca *ca) int len; int sock, i; struct sockaddr sadr; - char port[6]; + char port[6], path[32]; - snprintf(port, sizeof(port), "%u", (uint16_t) (8888 + ca->nr)); - sock = streamsock(port, AF_INET, &sadr); + if (ca->dd->cam_family == 1) { + snprintf(port, sizeof(port), "%u", (uint16_t) (8888 + ca->nr)); + sock = streamsock(port, AF_INET, &sadr); + } else if (ca->dd->cam_family == 2) { + snprintf(path, sizeof(path), "/var/run/resiplayer/cam%u", ca->nr); + sock = unixsock(path); + } else { + sock = -1; + } if (listen(sock, 4) < 0) { dbgprintf(DEBUG_CA, "listen error"); return; @@ -466,6 +501,8 @@ static int mmi_close_callback(void *arg, uint8_t slot_id, uint16_t snum, struct dddvb_ca *ca = arg; ca->mmi_state = MMI_STATE_CLOSED; + if (ca->dd->cam_proto == 2) + sendstringx(ca->sock, "CLOSE", 0, NULL); return 0; } @@ -492,6 +529,8 @@ static int mmi_display_control_callback(void *arg, uint8_t slot_id, uint16_t snu en50221_app_mmi_display_reply(ca->stdcam->mmi_resource, snum, MMI_DISPLAY_REPLY_ID_MMI_MODE_ACK, &reply); ca->mmi_state = MMI_STATE_OPEN; + if (ca->dd->cam_proto == 2) + sendstringx(ca->sock, "OPEN", 0, NULL); return 0; } @@ -502,7 +541,10 @@ static int mmi_enq_callback(void *arg, uint8_t slot_id, uint16_t snum, struct dddvb_ca *ca = arg; if (ca->sock >= 0) { + if (ca->dd->cam_proto == 1) sendstring(ca->sock, "%.*s: ", text_size, text); + if (ca->dd->cam_proto == 2) + sendstringx(ca->sock, "ENQ", text_size, text); } //mmi_enq_blind = blind_answer; //mmi_enq_length = expected_answer_length; @@ -520,7 +562,7 @@ static int mmi_menu_callback(void *arg, uint8_t slot_id, uint16_t snum, uint32_t i; struct dddvb_ca *ca = arg; - if (ca->sock >= 0) { + if ((ca->sock >= 0) && (ca->dd->cam_proto == 1)) { if (title->text_length) sendstring(ca->sock, "%.*s\n", title->text_length, title->text); if (sub_title->text_length) @@ -530,6 +572,13 @@ static int mmi_menu_callback(void *arg, uint8_t slot_id, uint16_t snum, if (bottom->text_length) sendstring(ca->sock, "%.*s\n", bottom->text_length, bottom->text); } + if (ca->dd->cam_proto == 2) { + sendstringx(ca->sock, "MENU", title->text_length, title->text); + sendstringx(ca->sock, "MSUB", sub_title->text_length, sub_title->text); + for (i = 0; i < item_count; i++) + sendstringx(ca->sock, "ITEM", items[i].text_length, items[i].text); + sendstringx(ca->sock, "MEND", bottom->text_length, bottom->text); + } ca->mmi_state = MMI_STATE_MENU; return 0; } diff --git a/lib/src/config.c b/lib/src/config.c index 53e9943..05e23d9 100644 --- a/lib/src/config.c +++ b/lib/src/config.c @@ -41,7 +41,7 @@ int parse_config(struct dddvb *dd, char *name, char *sec, memcpy(fname + config_len, "dddvb.conf", 11); if ((f = fopen (fname, "r")) == NULL) { - printf("config file %s not found\n", fname); + dprintf(2, "config file %s not found\n", fname); return -1; } diff --git a/lib/src/dddvb.c b/lib/src/dddvb.c index aa85a8b..b011a04 100644 --- a/lib/src/dddvb.c +++ b/lib/src/dddvb.c @@ -8,7 +8,7 @@ LIBDDDVB_EXPORTED struct dddvb *global_dd = NULL; LIBDDDVB_EXPORTED pthread_mutex_t dddvb_mutex = PTHREAD_MUTEX_INITIALIZER; void __attribute__ ((constructor)) setup(void) { - printf("SETUP\n"); + //printf("SETUP\n"); } LIBDDDVB_EXPORTED struct dddvb_fe *dddvb_fe_alloc_num(struct dddvb *dd, uint32_t type, uint32_t num) diff --git a/lib/src/dddvb.h b/lib/src/dddvb.h index 4f2390f..a478bb2 100644 --- a/lib/src/dddvb.h +++ b/lib/src/dddvb.h @@ -152,6 +152,9 @@ struct dddvb { struct dddvb_fe dvbfe[DDDVB_MAX_DVB_FE]; struct dddvb_ca dvbca[DDDVB_MAX_DVB_CA]; + unsigned int cam_family; + unsigned int cam_proto; + unsigned int cam_port; unsigned int get_ts:1; }; diff --git a/lib/src/dvb.c b/lib/src/dvb.c index 72e9703..9a1f840 100644 --- a/lib/src/dvb.c +++ b/lib/src/dvb.c @@ -111,6 +111,7 @@ static int set_fe_input(struct dddvb_fe *fe, uint32_t fr, { .cmd = DTV_INVERSION, .u.data = INVERSION_AUTO }, { .cmd = DTV_SYMBOL_RATE, .u.data = sr }, { .cmd = DTV_INNER_FEC, .u.data = FEC_AUTO }, + { .cmd = DTV_ROLLOFF, .u.data = ROLLOFF_AUTO }, }; struct dtv_properties c; int ret; @@ -128,7 +129,7 @@ static int set_fe_input(struct dddvb_fe *fe, uint32_t fr, } if (input != DDDVB_UNDEF) set_property(fd, DTV_INPUT, input); - fprintf(stderr, "bw =%u\n", fe->param.param[PARAM_BW_HZ]); + //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) @@ -181,7 +182,16 @@ static int diseqc(int fd, int sat, int hor, int band) return 0; } -static int set_en50494(struct dddvb_fe *fe, uint32_t freq, uint32_t sr, +static int set_vol_tone(int fd, int hor, int band) +{ + if (ioctl(fd, FE_SET_TONE, band ? SEC_TONE_ON : SEC_TONE_OFF)) + perror("FE_SET_TONE failed"); + if (ioctl(fd, FE_SET_VOLTAGE, hor ? SEC_VOLTAGE_18 : SEC_VOLTAGE_13) == -1) + perror("FE_SET_VOLTAGE failed"); + dbgprintf(DEBUG_DVB, "set_vol_tone hor=%u, band=%u\n", hor, band); +} + +static int set_en50494(struct dddvb_fe *fe, uint32_t freq_khz, uint32_t sr, int sat, int hor, int band, uint32_t slot, uint32_t ubfreq, fe_delivery_system_t ds) @@ -193,8 +203,10 @@ static int set_en50494(struct dddvb_fe *fe, uint32_t freq, uint32_t sr, uint16_t t; uint32_t input = 3 & (sat >> 6); int fd = fe->fd; + uint32_t freq = (freq_khz + 2000) / 4000; + int32_t fdiff = freq_khz - freq * 1000; - t = (freq + ubfreq + 2) / 4 - 350; + t = (freq_khz / 1000 + ubfreq + 2) / 4 - 350; hor &= 1; cmd.msg[3] = ((t & 0x0300) >> 8) | @@ -218,7 +230,7 @@ static int set_en50494(struct dddvb_fe *fe, uint32_t freq, uint32_t sr, cmd.msg[0], cmd.msg[1], cmd.msg[2], cmd.msg[3], cmd.msg[4]); } -static int set_en50607(struct dddvb_fe *fe, uint32_t freq, uint32_t sr, +static int set_en50607(struct dddvb_fe *fe, uint32_t freq_khz, uint32_t sr, int sat, int hor, int band, uint32_t slot, uint32_t ubfreq, fe_delivery_system_t ds) @@ -227,11 +239,13 @@ static int set_en50607(struct dddvb_fe *fe, uint32_t freq, uint32_t sr, .msg = {0x70, 0x00, 0x00, 0x00, 0x00}, .msg_len = 4 }; + uint32_t freq = (freq_khz + 500) / 1000; + int32_t fdiff = freq_khz - freq * 1000; uint32_t t = freq - 100; uint32_t input = 3 & (sat >> 6); int fd = fe->fd; - //printf("input = %u, sat = %u\n", input, sat&0x3f); + dbgprintf(DEBUG_DVB, "input = %u, sat = %u\n", input, sat&0x3f); hor &= 1; cmd.msg[1] = slot << 3; cmd.msg[1] |= ((t >> 8) & 0x07); @@ -250,11 +264,11 @@ static int set_en50607(struct dddvb_fe *fe, uint32_t freq, uint32_t sr, if (ioctl(fd, FE_SET_VOLTAGE, SEC_VOLTAGE_13) == -1) perror("FE_SET_VOLTAGE failed"); - set_fe_input(fe, ubfreq * 1000, sr, ds, input); + set_fe_input(fe, ubfreq * 1000 + fdiff, sr, ds, input); dbgprintf(DEBUG_DVB, "EN50607 %02x %02x %02x %02x\n", cmd.msg[0], cmd.msg[1], cmd.msg[2], cmd.msg[3]); - dbgprintf(DEBUG_DVB, "EN50607 freq %u sr %u hor %u\n", - freq, sr, hor); + dbgprintf(DEBUG_DVB, "EN50607 freq %u ubfreq %u fdiff %d sr %u hor %u\n", + freq, ubfreq, fdiff, sr, hor); } @@ -288,13 +302,20 @@ static int tune_sat(struct dddvb_fe *fe) freq = lofs - freq; } #endif - if (freq > 2100000) { + if (freq > 3000000) { if (lofs) hi = (freq > lofs) ? 1 : 0; - if (hi) - freq -= fe->lof2[lnbc]; - else - freq -= fe->lof1[lnbc]; + if (lofs > 10000000) { + if (hi) + freq -= fe->lof2[lnbc]; + else + freq -= fe->lof1[lnbc]; + } else { + if (hi) + freq = fe->lof2[lnbc] - freq; + else + freq = fe->lof1[lnbc] - freq; + } } dbgprintf(DEBUG_DVB, "tune_sat IF=%u\n", freq); if (fe->first) { @@ -307,23 +328,28 @@ static int tune_sat(struct dddvb_fe *fe) dbgprintf(DEBUG_DVB, "scif_type = %u\n", fe->scif_type); if (fe->scif_type == 1) { pthread_mutex_lock(&fe->dd->uni_lock); - set_en50494(fe, freq / 1000, fe->param.param[PARAM_SR], + set_en50494(fe, freq, fe->param.param[PARAM_SR], lnb, fe->param.param[PARAM_POL], hi, fe->scif_slot, fe->scif_freq, ds); pthread_mutex_unlock(&fe->dd->uni_lock); } else if (fe->scif_type == 2) { pthread_mutex_lock(&fe->dd->uni_lock); - set_en50607(fe, freq / 1000, fe->param.param[PARAM_SR], + set_en50607(fe, freq, fe->param.param[PARAM_SR], lnb, fe->param.param[PARAM_POL], hi, fe->scif_slot, fe->scif_freq, ds); pthread_mutex_unlock(&fe->dd->uni_lock); } else { - uint32_t input = lnb; + uint32_t input = fe->param.param[PARAM_SRC]; - if (input != DDDVB_UNDEF) + if (input != DDDVB_UNDEF) { input = 3 & (input >> 6); - //set_property(fe->fd, DTV_INPUT, 3 & (lnb >> 6)); - diseqc(fe->fd, lnb, fe->param.param[PARAM_POL], hi); + dbgprintf(DEBUG_DVB, "input = %u\n", input); + set_property(fe->fd, DTV_INPUT, input); + } + if (fe->scif_type == 3) + set_vol_tone(fe->fd, fe->param.param[PARAM_POL], hi); + else + diseqc(fe->fd, lnb, fe->param.param[PARAM_POL], hi); set_fe_input(fe, freq, fe->param.param[PARAM_SR], ds, input); } } @@ -346,7 +372,7 @@ static int tune_c(struct dddvb_fe *fe) struct dtv_properties c; int ret; - printf("tune_c()\n"); + dbgprintf(DEBUG_DVB, "tune_c()\n"); set_property(fe->fd, DTV_DELIVERY_SYSTEM, SYS_DVBC_ANNEX_A); c.num = ARRAY_SIZE(p); @@ -373,7 +399,7 @@ static int tune_j83b(struct dddvb_fe *fe) struct dtv_properties c; int ret; - printf("tune_j83b()\n"); + dbgprintf(DEBUG_DVB, "tune_j83b()\n"); set_property(fe->fd, DTV_DELIVERY_SYSTEM, SYS_DVBC_ANNEX_B); c.num = ARRAY_SIZE(p); @@ -509,11 +535,37 @@ static int tune_isdbt(struct dddvb_fe *fe) return 0; } +static int tune_isdbs(struct dddvb_fe *fe) +{ + struct dtv_property p[] = { + { .cmd = DTV_CLEAR }, + { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ]}, + //{ .cmd = DTV_SYMBOL_RATE, .u.data = fe->param.param[PARAM_SR] }, + //{ .cmd = DTV_TUNE }, + }; + struct dtv_properties c; + int ret; + + set_property(fe->fd, DTV_DELIVERY_SYSTEM, SYS_ISDBS); + + 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; + } + if (fe->param.param[PARAM_ISI] != DDDVB_UNDEF) + set_property(fe->fd, DTV_STREAM_ID, fe->param.param[PARAM_ISI]); + set_property(fe->fd, DTV_TUNE, 0); + return 0; +} + static int tune(struct dddvb_fe *fe) { int ret; - printf("tune()\n"); + dbgprintf(DEBUG_DVB, "tune()\n"); switch (fe->param.param[PARAM_MSYS]) { case SYS_DVBS: case SYS_DVBS2: @@ -537,6 +589,9 @@ static int tune(struct dddvb_fe *fe) case SYS_ISDBT: ret = tune_isdbt(fe); break; + case SYS_ISDBS: + ret = tune_isdbs(fe); + break; default: break; } @@ -571,7 +626,6 @@ static int open_fe(struct dddvb_fe *fe) sprintf(fname, "/dev/dvb/adapter%d/frontend%d", fe->anum, fe->fnum); fe->fd = open(fname, O_RDWR); - printf("open = %d\n", fe->fd); if (fe->fd < 0) return -1; return 0; @@ -678,7 +732,7 @@ void dddvb_fe_handle(struct dddvb_fe *fe) } else { max = 1; nolock++; - if (nolock > 100) + if (nolock > 10) fe->tune = 1; } break; @@ -720,6 +774,8 @@ int dddvb_fe_tune(struct dddvb_fe *fe, struct dddvb_params *p) memcpy(fe->n_param.param, p->param, sizeof(fe->n_param.param)); fe->n_tune = 1; pthread_mutex_unlock(&fe->mutex); + while(fe->n_tune) usleep(10000); + while(fe->tune != 2) usleep(10000); return ret; } @@ -924,6 +980,31 @@ void lnb_config(struct dddvb *dd, char *name, char *val) } } +void ca_config(struct dddvb *dd, char *name, char *val) +{ + if (!name || !val) + return; + char *p = strpbrk(val, "\r\n"); + if (p) + *p = 0; + if (!strcasecmp(name, "family")) { + if (!strcasecmp(val, "tcp")) { + dd->cam_family = 1; + } else if (!strcasecmp(val, "unix")) { + dd->cam_family = 2; + } + return; + } + if (!strcasecmp(name, "proto")) { + dd->cam_proto = strtoul(val, NULL, 10); + return; + } + if (!strcasecmp(name, "port")) { + dd->cam_port = strtoul(val, NULL, 10); + return; + } +} + int dddvb_dvb_init(struct dddvb *dd) { pthread_mutex_init(&dd->uni_lock, 0); @@ -931,6 +1012,23 @@ int dddvb_dvb_init(struct dddvb *dd) parse_config(dd, "", "scif", &scif_config); set_lnb(dd, 0, 0, 9750000, 10600000, 11700000); parse_config(dd, "", "LNB", &lnb_config); + parse_config(dd, "", "CA", &ca_config); + { + if (dd->cam_family == 0) + dd->cam_family = 1; + if (dd->cam_proto == 0) { + switch (dd->cam_family) { + case 1: + dd->cam_proto = 1; + break; + case 2: + dd->cam_proto = 2; + break; + } + } + if (dd->cam_port == 0) + dd->cam_port = 8888; + } scan_dvbca(dd); } diff --git a/lib/src/dvb_quality.c b/lib/src/dvb_quality.c index ecef831..53d8a17 100644 --- a/lib/src/dvb_quality.c +++ b/lib/src/dvb_quality.c @@ -329,7 +329,7 @@ static void calc_lq(struct dddvb_fe *fe) { struct dtv_fe_stats st; 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, freq, rate; get_property(fe->fd, DTV_TRANSMISSION_MODE, &fe->pls_code); dbgprintf(DEBUG_DVB, "fe%d: pls=0x%02x\n", fe->nr, fe->pls_code); @@ -362,6 +362,10 @@ static void calc_lq(struct dddvb_fe *fe) dbgprintf(DEBUG_DVB, "fe%d: snr=%lld ber=%llu/%llu\n", fe->nr, snr, ber_num, ber_den); dbgprintf(DEBUG_DVB, "fe%d: fec=%u mod=%u\n", fe->nr, fec, mod); + get_property(fe->fd, DTV_FREQUENCY, &freq); + dbgprintf(DEBUG_DVB, "fe%d: actual frequency=%u\n", fe->nr, freq); + get_property(fe->fd, DTV_SYMBOL_RATE, &rate); + dbgprintf(DEBUG_DVB, "fe%d: actual symbol rate=%u\n", fe->nr, rate); switch (fe->n_param.param[PARAM_MSYS]) { case SYS_DVBS: quality = dvbsq(snr, fec, ber_num, ber_den); diff --git a/lib/src/tools.c b/lib/src/tools.c index 4bacb8a..9c787b8 100644 --- a/lib/src/tools.c +++ b/lib/src/tools.c @@ -4,6 +4,7 @@ #include #include #include +#include int sendlen(int sock, char *buf, int len) @@ -12,7 +13,7 @@ int sendlen(int sock, char *buf, int len) for (todo = len; todo; todo -= done, buf += done) if ((done = send(sock, buf, todo, 0)) < 0) { - printf("sendlen error\n"); + dprintf(2, "sendlen error\n"); return done; } return len; @@ -33,6 +34,34 @@ int sendstring(int sock, char *fmt, ...) return len; } +int sendstringx(int sock, const char *label, uint32_t text_length, const uint8_t *text) +{ + if (sock < 0) + return(-1); + + uint8_t buf[strlen(label) + 1 + text_length * 3 + 2]; + + strcpy(buf, label); + int len = strlen(buf); + buf[len++] = 0x20; + while (text_length--) { + int c = *text++; + if (c == 0x5C) { + buf[len++] = 0x5C; + buf[len++] = 0x5C; + } else if ((c < 0x20) || (c > 0x7E)) { + buf[len++] = 0x5C; + snprintf(buf+len, 3, "%02X", c); + len += 2; + } else { + buf[len++] = (uint8_t) c; + } + } + buf[len++] = 0x0A; + sendlen(sock, buf, len); + return(len); +} + time_t mtime(time_t *t) { struct timespec ts; diff --git a/lib/src/tools.h b/lib/src/tools.h index 06c8593..d09916d 100644 --- a/lib/src/tools.h +++ b/lib/src/tools.h @@ -4,5 +4,6 @@ time_t mtime(time_t *t); int sendlen(int sock, char *buf, int len); int sendstring(int sock, char *fmt, ...); +int sendstringx(int sock, const char *label, uint32_t text_length, const uint8_t *text); #endif /* _DDDVB_TOOLS_H_ */