From ee3e352c0c04fc2609a6d208f75c80b92072e9da Mon Sep 17 00:00:00 2001 From: none Date: Wed, 15 Jan 2020 12:32:34 +0100 Subject: [PATCH 01/55] add some fallthrough comments --- ddbridge/ddbridge-core.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ddbridge/ddbridge-core.c b/ddbridge/ddbridge-core.c index b9db99d..b75f579 100644 --- a/ddbridge/ddbridge-core.c +++ b/ddbridge/ddbridge-core.c @@ -328,6 +328,7 @@ static int ddb_buffers_alloc(struct ddb *dev) if (dma_alloc(dev->pdev, port->input[0]->dma, 0) < 0) return -1; + /* fallthrough */ case DDB_PORT_MOD: if (port->output->dma) if (dma_alloc(dev->pdev, @@ -1792,6 +1793,7 @@ static int dvb_input_attach(struct ddb_input *input) osc24 = 0; else osc24 = 1; + /* fallthrough */ case DDB_TUNER_DVBCT2_SONY_P: case DDB_TUNER_DVBC2T2_SONY_P: case DDB_TUNER_ISDBT_SONY_P: @@ -1808,6 +1810,7 @@ static int dvb_input_attach(struct ddb_input *input) break; case DDB_TUNER_DVBC2T2I_SONY: osc24 = 1; + /* fallthrough */ case DDB_TUNER_DVBCT2_SONY: case DDB_TUNER_DVBC2T2_SONY: case DDB_TUNER_ISDBT_SONY: @@ -2265,7 +2268,8 @@ static int ddb_port_attach(struct ddb_port *port) ret = ddb_ci_attach(port, ci_bitrate); if (ret < 0) break; - case DDB_PORT_LOOP: + /* fallthrough */ + case DDB_PORT_LOOP: ret = dvb_register_device(port->dvb[0].adap, &port->dvb[0].dev, &dvbdev_ci, (void *)port->output, @@ -4661,6 +4665,7 @@ int ddb_exit_ddbridge(int stage, int error) default: case 2: destroy_workqueue(ddb_wq); + /* fallthrough */ case 1: ddb_class_destroy(); } From 74e040f020dd74ca4f65aaafa68b4e4023412271 Mon Sep 17 00:00:00 2001 From: none Date: Wed, 15 Jan 2020 15:27:01 +0100 Subject: [PATCH 02/55] unset iq_mode flag in stop_iq --- ddbridge/ddbridge-sx8.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/ddbridge/ddbridge-sx8.c b/ddbridge/ddbridge-sx8.c index 468f6d4..e0ee5bf 100644 --- a/ddbridge/ddbridge-sx8.c +++ b/ddbridge/ddbridge-sx8.c @@ -162,6 +162,8 @@ static int mci_set_tuner(struct dvb_frontend *fe, u32 tuner, u32 on) static int stop_iq(struct dvb_frontend *fe) { 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; if (!state->iq_started) @@ -172,6 +174,7 @@ static int stop_iq(struct dvb_frontend *fe) ddb_mci_cmd(&state->mci, &cmd, NULL); ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL); state->iq_started = 0; + sx8_base->iq_mode = 0; return 0; } From 2c6530aa8dee4b2c7c25b22c855531960939bae2 Mon Sep 17 00:00:00 2001 From: Marcus Metzler Date: Wed, 15 Jan 2020 15:47:13 +0100 Subject: [PATCH 03/55] write tuning info to stderr instead of stdout when writing dvr to stdout --- lib/ddzap.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/ddzap.c b/lib/ddzap.c index f403c5c..3119fb9 100644 --- a/lib/ddzap.c +++ b/lib/ddzap.c @@ -244,7 +244,7 @@ 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", + fprintf(stderr,"stat=%02x, str=%lld.%03llddB, snr=%lld.%03llddB \n", stat, str/1000, abs(str%1000), cnr/1000, abs(cnr%1000)); sleep(1); } From a5d0a9718bd2b746881e4a81c42c3cdf59d0bff4 Mon Sep 17 00:00:00 2001 From: none Date: Thu, 16 Jan 2020 10:43:15 +0100 Subject: [PATCH 04/55] add a DVB-S2 22 MSymb mode --- ddbridge/ddbridge-modulator.c | 5 +++++ include/linux/dvb/mod.h | 1 + 2 files changed, 6 insertions(+) diff --git a/ddbridge/ddbridge-modulator.c b/ddbridge/ddbridge-modulator.c index 531f418..f1c2cfd 100644 --- a/ddbridge/ddbridge-modulator.c +++ b/ddbridge/ddbridge-modulator.c @@ -1519,6 +1519,7 @@ static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate) u32 cic, inc; switch (rate) { + /* 2^31 * freq*4*cic / 245.76Mhz */ case SYS_DVBT_6: inc = 1917396114; cic = 8; @@ -1536,6 +1537,10 @@ static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate) inc = 1988410754; cic = 7; break; + case SYS_DVBS2_22: + inc = 1922389333; + cic = 5; + break; default: return -EINVAL; } diff --git a/include/linux/dvb/mod.h b/include/linux/dvb/mod.h index 49fd1a8..3c1d5e4 100644 --- a/include/linux/dvb/mod.h +++ b/include/linux/dvb/mod.h @@ -41,6 +41,7 @@ enum mod_output_rate { SYS_DVBT_7, SYS_DVBT_8, SYS_ISDBT_6 = 16, + SYS_DVBS2_22 = 32, }; From 75a4a733f22756e1c39b75dc1e094008a51c5e55 Mon Sep 17 00:00:00 2001 From: none Date: Thu, 16 Jan 2020 10:44:23 +0100 Subject: [PATCH 05/55] add bandwidth defaults --- lib/src/dvb.c | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/src/dvb.c b/lib/src/dvb.c index f0e0cbb..3245c8e 100644 --- a/lib/src/dvb.c +++ b/lib/src/dvb.c @@ -128,6 +128,9 @@ 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]); + 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) set_property(fd, DTV_STREAM_ID, fe->param.param[PARAM_ISI]); if (fe->param.param[PARAM_SSI] != DDDVB_UNDEF) @@ -374,7 +377,8 @@ static int tune_terr(struct dddvb_fe *fe) struct dtv_property p[] = { { .cmd = DTV_CLEAR }, { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 }, - { .cmd = DTV_BANDWIDTH_HZ, .u.data = fe->param.param[PARAM_BW_HZ] }, + { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ? + fe->param.param[PARAM_BW_HZ] : 8000000 }, { .cmd = DTV_TUNE }, }; struct dtv_properties c; @@ -422,7 +426,8 @@ static int tune_c2(struct dddvb_fe *fe) struct dtv_property p[] = { { .cmd = DTV_CLEAR }, { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 }, - { .cmd = DTV_BANDWIDTH_HZ, .u.data = fe->param.param[PARAM_BW_HZ] }, + { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ? + fe->param.param[PARAM_BW_HZ] : 8000000 }, { .cmd = DTV_STREAM_ID, .u.data = fe->param.param[PARAM_PLP] }, { .cmd = DTV_TUNE }, }; @@ -446,7 +451,8 @@ static int tune_terr2(struct dddvb_fe *fe) struct dtv_property p[] = { { .cmd = DTV_CLEAR }, { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 }, - { .cmd = DTV_BANDWIDTH_HZ, .u.data = fe->param.param[PARAM_BW_HZ] }, + { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ? + fe->param.param[PARAM_BW_HZ] : 8000000 }, { .cmd = DTV_STREAM_ID, .u.data = fe->param.param[PARAM_PLP] }, { .cmd = DTV_TUNE }, }; @@ -470,7 +476,8 @@ static int tune_isdbt(struct dddvb_fe *fe) struct dtv_property p[] = { { .cmd = DTV_CLEAR }, { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000 }, - { .cmd = DTV_BANDWIDTH_HZ, .u.data = fe->param.param[PARAM_BW_HZ] }, + { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ? + fe->param.param[PARAM_BW_HZ] : 6000000 }, { .cmd = DTV_TUNE }, }; struct dtv_properties c; From b185b5fb667417eb84baa6ed310ce5a9170c6256 Mon Sep 17 00:00:00 2001 From: none Date: Thu, 16 Jan 2020 10:45:02 +0100 Subject: [PATCH 06/55] undef bandwidth add H/V as alternatives for h/v --- lib/ddzap.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ddzap.c b/lib/ddzap.c index 3119fb9..f3079e8 100644 --- a/lib/ddzap.c +++ b/lib/ddzap.c @@ -29,7 +29,7 @@ int main(int argc, char **argv) struct dddvb *dd; struct dddvb_fe *fe; struct dddvb_params p; - uint32_t bandwidth = 8000000, frequency = 0, symbol_rate = 0, pol = DDDVB_UNDEF; + uint32_t bandwidth = DDDVB_UNDEF, frequency = 0, symbol_rate = 0, pol = DDDVB_UNDEF; uint32_t id = DDDVB_UNDEF, ssi = DDDVB_UNDEF, num = DDDVB_UNDEF, source = 0; uint32_t mtype= DDDVB_UNDEF; uint32_t verbosity = 0; @@ -147,9 +147,9 @@ int main(int argc, char **argv) delsys = SYS_ISDBT; break; case 'p': - if (!strcmp(optarg, "h")) + if (!strcmp(optarg, "h") || !strcmp(optarg, "H")) pol = 1; - if (!strcmp(optarg, "v")) + if (!strcmp(optarg, "v") || !strcmp(optarg, "V")) pol = 0; break; case 'h': @@ -159,7 +159,7 @@ int main(int argc, char **argv) " [-o (write dvr to stdout)]\n" "\n" " delivery_system = C,S,S2,T,T2,J83B,ISDBC,ISDBT\n" - " polarity = h,v\n" + " polarity = h/H,v/V\n" "\n"); exit(-1); default: From fe80bc1154d8bd093a835a26c04d874fdc09c0a0 Mon Sep 17 00:00:00 2001 From: none Date: Thu, 16 Jan 2020 10:49:56 +0100 Subject: [PATCH 07/55] - remove unused code - only report warning on FW failure --- frontends/mxl5xx.c | 19 +++---------------- 1 file changed, 3 insertions(+), 16 deletions(-) diff --git a/frontends/mxl5xx.c b/frontends/mxl5xx.c index af60e1e..078f33d 100644 --- a/frontends/mxl5xx.c +++ b/frontends/mxl5xx.c @@ -357,19 +357,6 @@ static int update_by_mnemonic(struct mxl *state, return stat; } -#if 0 -static void extract_from_mnemonic(u32 regAddr, u8 lsbPos, u8 width, - u32 *toAddr, u8 *toLsbPos, u8 *toWidth) -{ - if (toAddr) - *toAddr = regAddr; - if (toLsbPos) - *toLsbPos = lsbPos; - if (toWidth) - *toWidth = width; -} -#endif - static int firmware_is_alive(struct mxl *state) { u32 hb0, hb1; @@ -379,10 +366,10 @@ static int firmware_is_alive(struct mxl *state) msleep(20); if (read_register(state, HYDRA_HEAR_BEAT, &hb1)) return 0; - if (hb1 == hb0) + if (hb1 == hb0) { + pr_warn("mxl5xx: Hydra FW not running!\n"); return 0; - - pr_info("mxl5xx: Hydra FW alive. Hail!\n"); + } return 1; } From b3848a362d42816d0097ad68f0e1c1450cb7392a Mon Sep 17 00:00:00 2001 From: none Date: Thu, 16 Jan 2020 10:51:19 +0100 Subject: [PATCH 08/55] add multistream flags some user space software needs this for T2 mutlistream (although it makes no sense, T2 always demands multistream capability) --- frontends/cxd2843.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/frontends/cxd2843.c b/frontends/cxd2843.c index 8695207..c0d10f2 100644 --- a/frontends/cxd2843.c +++ b/frontends/cxd2843.c @@ -2502,7 +2502,8 @@ static struct dvb_frontend_ops common_ops_2854 = { FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | - FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION + FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION | + FE_CAN_MULTISTREAM }, .release = release, .sleep = sleep, @@ -2535,7 +2536,8 @@ static struct dvb_frontend_ops common_ops_2843 = { FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | - FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION + FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION | + FE_CAN_MULTISTREAM }, .release = release, .sleep = sleep, @@ -2573,7 +2575,8 @@ static struct dvb_frontend_ops common_ops_2837 = { FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | - FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION + FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION | + FE_CAN_MULTISTREAM }, .release = release, .sleep = sleep, From 2610424e1c4db8d6a9db1b5171b787cbd57a8ba2 Mon Sep 17 00:00:00 2001 From: none Date: Thu, 16 Jan 2020 10:53:26 +0100 Subject: [PATCH 09/55] adapt to mainline kernel version --- dvb-core/dvb_ca_en50221.c | 110 +++++++++++++++++++------------------- 1 file changed, 54 insertions(+), 56 deletions(-) diff --git a/dvb-core/dvb_ca_en50221.c b/dvb-core/dvb_ca_en50221.c index 500357c..87db54f 100644 --- a/dvb-core/dvb_ca_en50221.c +++ b/dvb-core/dvb_ca_en50221.c @@ -1,3 +1,4 @@ + // SPDX-License-Identifier: GPL-2.0-or-later /* * dvb_ca.c: generic DVB functions for EN50221 CAM interfaces * @@ -11,18 +12,6 @@ * * Copyright (C) 1999-2002 Ralph Metzler * & Marcus Metzler for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ #define pr_fmt(fmt) "dvb_ca_en50221: " fmt @@ -31,10 +20,13 @@ #include #include #include +#include +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18)) +#include +#endif #include #include #include -#include #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 11, 0)) #include #else @@ -211,7 +203,7 @@ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, * @hlen: Number of bytes in haystack. * @needle: Buffer to find. * @nlen: Number of bytes in needle. - * @return Pointer into haystack needle was found at, or NULL if not found. + * return: Pointer into haystack needle was found at, or NULL if not found. */ static char *findstr(char *haystack, int hlen, char *needle, int nlen) { @@ -231,7 +223,7 @@ static char *findstr(char *haystack, int hlen, char *needle, int nlen) /* ************************************************************************** */ /* EN50221 physical interface functions */ -/** +/* * dvb_ca_en50221_check_camstatus - Check CAM status. */ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot) @@ -280,9 +272,9 @@ static int dvb_ca_en50221_check_camstatus(struct dvb_ca_private *ca, int slot) * @ca: CA instance. * @slot: Slot on interface. * @waitfor: Flags to wait for. - * @timeout_ms: Timeout in milliseconds. + * @timeout_hz: Timeout in milliseconds. * - * @return 0 on success, nonzero on error. + * return: 0 on success, nonzero on error. */ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, u8 waitfor, int timeout_hz) @@ -330,7 +322,7 @@ static int dvb_ca_en50221_wait_if_status(struct dvb_ca_private *ca, int slot, * @ca: CA instance. * @slot: Slot id. * - * @return 0 on success, nonzero on failure. + * return: 0 on success, nonzero on failure. */ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) { @@ -402,11 +394,11 @@ static int dvb_ca_en50221_link_init(struct dvb_ca_private *ca, int slot) * @ca: CA instance. * @slot: Slot id. * @address: Address to read from. Updated. - * @tupleType: Tuple id byte. Updated. - * @tupleLength: Tuple length. Updated. + * @tuple_type: Tuple id byte. Updated. + * @tuple_length: Tuple length. Updated. * @tuple: Dest buffer for tuple (must be 256 bytes). Updated. * - * @return 0 on success, nonzero on error. + * return: 0 on success, nonzero on error. */ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot, int *address, int *tuple_type, @@ -460,7 +452,7 @@ static int dvb_ca_en50221_read_tuple(struct dvb_ca_private *ca, int slot, * @ca: CA instance. * @slot: Slot id. * - * @return 0 on success, <0 on failure. + * return: 0 on success, <0 on failure. */ static int dvb_ca_en50221_parse_attributes(struct dvb_ca_private *ca, int slot) { @@ -637,10 +629,11 @@ 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 + * return: Number of bytes read, or < 0 on error */ static int dvb_ca_en50221_read_data(struct dvb_ca_private *ca, int slot, u8 *ebuf, int ecount) @@ -789,11 +782,11 @@ exit: * * @ca: CA instance. * @slot: Slot to write to. - * @ebuf: The data in this buffer is treated as a complete link-level packet to + * @buf: The data in this buffer is treated as a complete link-level packet to * be written. - * @count: Size of ebuf. + * @bytes_write: Size of ebuf. * - * @return Number of bytes written, or < 0 on error. + * return: Number of bytes written, or < 0 on error. */ static int dvb_ca_en50221_write_data(struct dvb_ca_private *ca, int slot, u8 *buf, int bytes_write) @@ -938,7 +931,7 @@ static int dvb_ca_en50221_slot_shutdown(struct dvb_ca_private *ca, int slot) /** * dvb_ca_en50221_camchange_irq - A CAMCHANGE IRQ has occurred. * - * @ca: CA instance. + * @pubca: CA instance. * @slot: Slot concerned. * @change_type: One of the DVB_CA_CAMCHANGE_* values. */ @@ -968,7 +961,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_camchange_irq); /** * dvb_ca_en50221_camready_irq - A CAMREADY IRQ has occurred. * - * @ca: CA instance. + * @pubca: CA instance. * @slot: Slot concerned. */ void dvb_ca_en50221_camready_irq(struct dvb_ca_en50221 *pubca, int slot) @@ -988,7 +981,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_camready_irq); /** * dvb_ca_en50221_frda_irq - An FR or DA IRQ has occurred. * - * @ca: CA instance. + * @pubca: CA instance. * @slot: Slot concerned. */ void dvb_ca_en50221_frda_irq(struct dvb_ca_en50221 *pubca, int slot) @@ -1096,7 +1089,7 @@ static void dvb_ca_en50221_thread_update_delay(struct dvb_ca_private *ca) * * @ca: CA instance. * @slot: Slot to process. - * @return: 0 .. no change + * return:: 0 .. no change * 1 .. CAM state changed */ @@ -1274,7 +1267,7 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca, ca->pub->slot_ts_enable(ca->pub, slot); sl->slot_state = DVB_CA_SLOTSTATE_RUNNING; dvb_ca_en50221_thread_update_delay(ca); - pr_err("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", + pr_info("dvb_ca adapter %d: DVB CAM detected and initialised successfully\n", ca->dvbdev->adapter->num); break; @@ -1317,7 +1310,7 @@ static void dvb_ca_en50221_thread_state_machine(struct dvb_ca_private *ca, mutex_unlock(&sl->slot_lock); } -/** +/* * Kernel thread which monitors CA slots for CAM changes, and performs data * transfers. */ @@ -1357,12 +1350,11 @@ static int dvb_ca_en50221_thread(void *data) * Real ioctl implementation. * NOTE: CA_SEND_MSG/CA_GET_MSG ioctls have userspace buffers passed to them. * - * @inode: Inode concerned. * @file: File concerned. * @cmd: IOCTL command. - * @arg: Associated argument. + * @parg: Associated argument. * - * @return 0 on success, <0 on error. + * return: 0 on success, <0 on error. */ static int dvb_ca_en50221_io_do_ioctl(struct file *file, unsigned int cmd, void *parg) @@ -1411,7 +1403,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file, struct dvb_ca_slot *sl; slot = info->num; - if ((slot > ca->slot_count) || (slot < 0)) { + if ((slot >= ca->slot_count) || (slot < 0)) { err = -EINVAL; goto out_unlock; } @@ -1441,12 +1433,11 @@ out_unlock: /** * Wrapper for ioctl implementation. * - * @inode: Inode concerned. * @file: File concerned. * @cmd: IOCTL command. * @arg: Associated argument. * - * @return 0 on success, <0 on error. + * return: 0 on success, <0 on error. */ static long dvb_ca_en50221_io_ioctl(struct file *file, unsigned int cmd, unsigned long arg) @@ -1462,7 +1453,7 @@ static long dvb_ca_en50221_io_ioctl(struct file *file, * @count: Size of source buffer. * @ppos: Position in file (ignored). * - * @return Number of bytes read, or <0 on error. + * return: Number of bytes read, or <0 on error. */ static ssize_t dvb_ca_en50221_io_write(struct file *file, const char __user *buf, size_t count, @@ -1495,6 +1486,11 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file, return -EFAULT; buf += 2; count -= 2; + if (slot >= ca->slot_count) + return -EINVAL; +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 14, 18)) + slot = array_index_nospec(slot, ca->slot_count); +#endif sl = &ca->slot_info[slot]; /* check if the slot is actually running */ @@ -1557,7 +1553,7 @@ exit: return status; } -/** +/* * Condition for waking up in dvb_ca_en50221_io_read_condition */ static int dvb_ca_en50221_io_read_condition(struct dvb_ca_private *ca, @@ -1614,7 +1610,7 @@ nextslot: * @count: Size of destination buffer. * @ppos: Position in file (ignored). * - * @return Number of bytes read, or <0 on error. + * return: Number of bytes read, or <0 on error. */ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) @@ -1723,7 +1719,7 @@ exit: * @inode: Inode concerned. * @file: File concerned. * - * @return 0 on success, <0 on failure. + * return: 0 on success, <0 on failure. */ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) { @@ -1773,7 +1769,7 @@ static int dvb_ca_en50221_io_open(struct inode *inode, struct file *file) * @inode: Inode concerned. * @file: File concerned. * - * @return 0 on success, <0 on failure. + * return: 0 on success, <0 on failure. */ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) { @@ -1802,30 +1798,33 @@ static int dvb_ca_en50221_io_release(struct inode *inode, struct file *file) * @file: File concerned. * @wait: poll wait table. * - * @return Standard poll mask. + * return: Standard poll mask. */ -static unsigned int dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)) +typedef unsigned int __poll_t; +#define EPOLLIN POLLIN +#endif +static __poll_t dvb_ca_en50221_io_poll(struct file *file, poll_table *wait) { struct dvb_device *dvbdev = file->private_data; struct dvb_ca_private *ca = dvbdev->priv; - unsigned int mask = 0; + __poll_t mask = 0; int slot; int result = 0; dprintk("%s\n", __func__); + poll_wait(file, &ca->wait_queue, wait); + if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) - mask |= POLLIN; + mask |= EPOLLIN; /* if there is something, return now */ if (mask) return mask; - /* wait for something to happen */ - poll_wait(file, &ca->wait_queue, wait); - if (dvb_ca_en50221_io_read_condition(ca, &result, &slot) == 1) - mask |= POLLIN; + mask |= EPOLLIN; return mask; } @@ -1859,11 +1858,11 @@ static const struct dvb_device dvbdev_ca = { * Initialise a new DVB CA EN50221 interface device. * * @dvb_adapter: DVB adapter to attach the new CA device to. - * @ca: The dvb_ca instance. + * @pubca: The dvb_ca instance. * @flags: Flags describing the CA device (DVB_CA_FLAG_*). * @slot_count: Number of slots supported. * - * @return 0 on success, nonzero on failure + * return: 0 on success, nonzero on failure */ int dvb_ca_en50221_init(struct dvb_adapter *dvb_adapter, struct dvb_ca_en50221 *pubca, int flags, int slot_count) @@ -1950,8 +1949,7 @@ EXPORT_SYMBOL(dvb_ca_en50221_init); /** * Release a DVB CA EN50221 interface device. * - * @ca_dev: The dvb_device_t instance for the CA device. - * @ca: The associated dvb_ca instance. + * @pubca: The associated dvb_ca instance. */ void dvb_ca_en50221_release(struct dvb_ca_en50221 *pubca) { From 0522573b46c8fba79b9a486314a80705d20d3b17 Mon Sep 17 00:00:00 2001 From: none Date: Thu, 16 Jan 2020 10:55:25 +0100 Subject: [PATCH 10/55] show GT link state on change --- ddbridge/ddbridge-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ddbridge/ddbridge-core.c b/ddbridge/ddbridge-core.c index b75f579..763046c 100644 --- a/ddbridge/ddbridge-core.c +++ b/ddbridge/ddbridge-core.c @@ -4319,7 +4319,7 @@ static void gtl_link_handler(void *priv) struct ddb *dev = (struct ddb *)priv; u32 regs = dev->link[0].info->regmap->gtl->base; - dev_info(dev->dev, "GT link change: %u\n", + dev_info(dev->dev, "GT link changed to %u\n", (1 & ddbreadl(dev, regs))); } From b946de7e44b19717a0b0ca48f61e190cb584e6aa Mon Sep 17 00:00:00 2001 From: none Date: Thu, 16 Jan 2020 10:55:58 +0100 Subject: [PATCH 11/55] comment cleanup --- ddbridge/ddbridge-mci.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ddbridge/ddbridge-mci.h b/ddbridge/ddbridge-mci.h index 1dc6121..e03ccc6 100644 --- a/ddbridge/ddbridge-mci.h +++ b/ddbridge/ddbridge-mci.h @@ -309,8 +309,8 @@ struct mci_command { struct { uint8_t flags; /* Bit 0 : 0 = VTM/SDR, 1 = SCAN, - Bit 1: 1 = Disable AGC, Bit 2: - 1 = Set Gain. */ + Bit 1: 1 = Disable AGC, + Bit 2: 1 = Set Gain. */ uint8_t roll_off; uint8_t rsvd1; uint8_t rsvd2; From aa1b5369ac37acf55783720b9415a5afc2beab50 Mon Sep 17 00:00:00 2001 From: none Date: Thu, 16 Jan 2020 10:57:53 +0100 Subject: [PATCH 12/55] make ddbridge device access count atomic --- ddbridge/ddbridge-core.c | 8 +++++--- ddbridge/ddbridge.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/ddbridge/ddbridge-core.c b/ddbridge/ddbridge-core.c index 763046c..64150d2 100644 --- a/ddbridge/ddbridge-core.c +++ b/ddbridge/ddbridge-core.c @@ -3340,7 +3340,7 @@ static int ddb_release(struct inode *inode, struct file *file) { struct ddb *dev = file->private_data; - dev->ddb_dev_users--; + atomic_inc(&dev->ddb_dev_users); return 0; } @@ -3348,9 +3348,10 @@ static int ddb_open(struct inode *inode, struct file *file) { struct ddb *dev = ddbs[iminor(inode)]; - if (dev->ddb_dev_users) + if (!atomic_dec_and_test(&dev->ddb_dev_users)) { + atomic_inc(&dev->ddb_dev_users); return -EBUSY; - dev->ddb_dev_users++; + } file->private_data = dev; return 0; } @@ -4278,6 +4279,7 @@ static int ddb_device_create(struct ddb *dev) return -ENOMEM; mutex_lock(&ddb_mutex); dev->nr = ddb_num; + atomic_set(&dev->ddb_dev_users, 1); ddbs[dev->nr] = dev; dev->ddb_dev = device_create(&ddb_class, dev->dev, MKDEV(ddb_major, dev->nr), diff --git a/ddbridge/ddbridge.h b/ddbridge/ddbridge.h index 2416880..370a2ba 100644 --- a/ddbridge/ddbridge.h +++ b/ddbridge/ddbridge.h @@ -450,7 +450,7 @@ struct ddb { struct ddb_dma odma[DDB_MAX_OUTPUT]; struct device *ddb_dev; - u32 ddb_dev_users; + atomic_t ddb_dev_users; u32 nr; u8 iobuf[1028]; From ade4caa718ad5417c2385051d661679c47a5a568 Mon Sep 17 00:00:00 2001 From: none Date: Thu, 16 Jan 2020 10:59:08 +0100 Subject: [PATCH 13/55] add some SPDX headers --- ddbridge/ddbridge-ns.c | 4 ++-- ddbridge/ddbridge.h | 7 +++---- dvb-core/Kconfig | 1 + dvb-core/Makefile | 1 + 4 files changed, 7 insertions(+), 6 deletions(-) diff --git a/ddbridge/ddbridge-ns.c b/ddbridge/ddbridge-ns.c index 8a48022..16a0700 100644 --- a/ddbridge/ddbridge-ns.c +++ b/ddbridge/ddbridge-ns.c @@ -1,9 +1,9 @@ /* * ddbridge-ns.c: Digital Devices PCIe bridge driver net streaming * - * Copyright (C) 2010-2017Marcus Metzler + * Copyright (C) 2010-2017 Digital Devices GmbH + * Marcus Metzler * Ralph Metzler - * Digital Devices GmbH * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License diff --git a/ddbridge/ddbridge.h b/ddbridge/ddbridge.h index 370a2ba..7fd0823 100644 --- a/ddbridge/ddbridge.h +++ b/ddbridge/ddbridge.h @@ -1,7 +1,8 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * ddbridge.h: Digital Devices PCIe bridge driver * - * Copyright (C) 2010-2019 Digital Devices GmbH + * Copyright (C) 2010-2017 Digital Devices GmbH * Marcus Metzler * Ralph Metzler * @@ -15,10 +16,8 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * - * * You should have received a copy of the GNU General Public License - * along with this program; if not, point your browser to - * http://www.gnu.org/copyleft/gpl.html + * along with this program. If not, see . */ #ifndef _DDBRIDGE_H_ diff --git a/dvb-core/Kconfig b/dvb-core/Kconfig index eeef94a..e7b2bdd 100644 --- a/dvb-core/Kconfig +++ b/dvb-core/Kconfig @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0-only # # DVB device configuration # diff --git a/dvb-core/Makefile b/dvb-core/Makefile index 85b0128..c8a5f48 100644 --- a/dvb-core/Makefile +++ b/dvb-core/Makefile @@ -1,3 +1,4 @@ +# SPDX-License-Identifier: GPL-2.0 # # Makefile for the kernel DVB device drivers. # From 6e57fd96b912b9708a88a72fe3688dd4195cd6e6 Mon Sep 17 00:00:00 2001 From: none Date: Sat, 18 Jan 2020 16:23:09 +0100 Subject: [PATCH 14/55] ddupdate test version --- apps/flashprog.c | 90 +---- apps/octonet/ddflash.c | 536 +---------------------------- apps/octonet/ddtest.c | 28 +- apps/octonet/ddupdate.c | 245 +++++++++++++ apps/octonet/flash.c | 740 ++++++++++++++++++++++++++++++++++++---- apps/octonet/flash.h | 31 +- 6 files changed, 985 insertions(+), 685 deletions(-) create mode 100644 apps/octonet/ddupdate.c diff --git a/apps/flashprog.c b/apps/flashprog.c index 399df7e..8546f9d 100644 --- a/apps/flashprog.c +++ b/apps/flashprog.c @@ -32,10 +32,12 @@ #include #include #include +#include #include "flash.h" +#include "flash.c" -void get_id(int ddb, struct ddb_id *ddbid) { +void get_ddid(int ddb, struct ddb_id *ddbid) { uint8_t id[4]; if (ioctl(ddb, IOCTL_DDB_ID, ddbid)>=0) @@ -147,8 +149,8 @@ int main(int argc, char **argv) } Flash = flashdetect(ddb, &SectorSize, &FlashSize); - get_id(ddb, &ddbid); -#if 1 + get_ddid(ddb, &ddbid); +#if 0 printf("%04x %04x %04x %04x %08x %08x\n", ddbid.vendor, ddbid.device, ddbid.subvendor, ddbid.subdevice, @@ -202,85 +204,13 @@ int main(int argc, char **argv) } else { int fh, i; int fsize; + char *name; if (!fname) - switch (ddbid.device) { - case 0x0002: - fname="DVBBridgeV1A_DVBBridgeV1A.bit"; - printf("Octopus 35\n"); - break; - case 0x0003: - fname="DVBBridgeV1B_DVBBridgeV1B.fpga"; - printf("Octopus\n"); - break; - case 0x0005: - fname="DVBBridgeV2A_DD01_0005_STD.fpga"; - printf("Octopus Classic\n"); - break; - case 0x0006: - fname="DVBBridgeV2A_DD01_0006_STD.fpga"; - printf("CineS2 V7\n"); - break; - case 0x0007: - fname="DVBBridgeV2A_DD01_0007_MXL.fpga"; - printf("Octopus 4/8\n"); - break; - case 0x0008: - fname="DVBBridgeV2A_DD01_0008_CXD.fpga"; - printf("Octopus 4/8\n"); - break; - case 0x0009: - fname="DVBBridgeV2A_DD01_0009_SX8.fpga"; - printf("Octopus MAXSX8\n"); - break; - case 0x000a: - fname="DVBBridgeV2A_DD01_000A_M4.fpga"; - printf("Octopus MAXM4\n"); - break; - case 0x0011: - fname="DVBBridgeV2B_DD01_0011.fpga"; - printf("Octopus CI\n"); - break; - case 0x0012: - fname="DVBBridgeV2B_DD01_0012_STD.fpga"; - printf("Octopus CI\n"); - break; - case 0x0013: - fname="DVBBridgeV2B_DD01_0013_PRO.fpga"; - printf("Octopus PRO\n"); - break; - case 0x0020: - fname="DVBBridgeV2C_DD01_0020.fpga"; - printf("Octopus GT Mini\n"); - break; - case 0x0201: - fname="DVBModulatorV1B_DVBModulatorV1B.bit"; - printf("Modulator\n"); - break; - case 0x0203: - fname="DVBModulatorV1B_DD01_0203.fpga"; - printf("Modulator Test\n"); - break; - case 0x0210: - fname="DVBModulatorV2A_DD01_0210.fpga"; - printf("Modulator V2\n"); - break; - case 0x0220: - fname="SDRModulatorV1A_DD01_0220.fpga"; - printf("SDRModulator ATV\n"); - break; - case 0x0221: - fname="SDRModulatorV1A_DD01_0221_IQ.fpga"; - printf("SDRModulator IQ\n"); - break; - case 0x0222: - fname="SDRModulatorV1A_DD01_0222_DVBT.fpga"; - printf("SDRModulator DVBT\n"); - break; - default: - printf("UNKNOWN\n"); - break; - } + fname = devid2fname(ddbid.device, &name); + if (name) + printf("Card: %s\n", name); + fh = open(fname, O_RDONLY); if (fh < 0 ) { printf("File %s not found \n", fname); diff --git a/apps/octonet/ddflash.c b/apps/octonet/ddflash.c index 0b2865c..3d32c42 100644 --- a/apps/octonet/ddflash.c +++ b/apps/octonet/ddflash.c @@ -36,6 +36,7 @@ #include #include "flash.h" +#include "flash.c" static int reboot(uint32_t off) { @@ -55,540 +56,6 @@ static int reboot(uint32_t off) return 0; } -struct ddflash { - int fd; - struct ddb_id id; - uint32_t version; - - uint32_t flash_type; - uint32_t sector_size; - uint32_t size; - - uint32_t bufsize; - uint32_t block_erase; - - uint8_t *buffer; -}; - -int flashwrite_pagemode(struct ddflash *ddf, int dev, uint32_t FlashOffset, - uint8_t LockBits, uint32_t fw_off) -{ - int err = 0; - uint8_t cmd[260]; - int i, j; - uint32_t flen, blen; - - blen = flen = lseek(dev, 0, SEEK_END) - fw_off; - if (blen % 0xff) - blen = (blen + 0xff) & 0xffffff00; - printf("blen = %u, flen = %u\n", blen, flen); - - do { - cmd[0] = 0x50; // EWSR - err = flashio(ddf->fd, cmd, 1, NULL, 0); - if (err < 0) - break; - - cmd[0] = 0x01; // WRSR - cmd[1] = 0x00; // BPx = 0, Unlock all blocks - err = flashio(ddf->fd, cmd, 2, NULL, 0); - if (err < 0) - break; - - for (i = 0; i < flen; i += 4096) { - if ((i & 0xFFFF) == 0) - printf(" Erase %08x\n", FlashOffset + i); - - cmd[0] = 0x06; // WREN - err = flashio(ddf->fd, cmd, 1, NULL, 0); - if (err < 0) - break; - - cmd[0] = 0x20; // Sector erase ( 4Kb) - cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF ); - cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF ); - cmd[3] = 0x00; - err = flashio(ddf->fd, cmd, 4, NULL, 0); - if (err < 0) - break; - - while (1) { - cmd[0] = 0x05; // RDRS - err = flashio(ddf->fd, cmd, 1, &cmd[0], 1); - if (err < 0) - break; - if ((cmd[0] & 0x01) == 0) - break; - } - if (err < 0) - break; - - } - if (err < 0) - break; - - for (j = blen - 256; j >= 0; j -= 256 ) { - uint32_t len = 256; - ssize_t rlen; - - if (lseek(dev, j + fw_off, SEEK_SET) < 0) { - printf("seek error\n"); - return -1; - } - if (flen - j < 256) { - len = flen - j; - memset(ddf->buffer, 0xff, 256); - } - rlen = read(dev, ddf->buffer, len); - if (rlen < 0 || rlen != len) { - printf("file read error %d,%d at %u\n", rlen, errno, j); - return -1; - } - printf ("write %u bytes at %08x\n", len, j); - - - if ((j & 0xFFFF) == 0) - printf(" Programm %08x\n", FlashOffset + j); - - cmd[0] = 0x06; // WREN - err = flashio(ddf->fd, cmd, 1, NULL, 0); - if (err < 0) - break; - - cmd[0] = 0x02; // PP - cmd[1] = ( (( FlashOffset + j ) >> 16) & 0xFF ); - cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF ); - cmd[3] = 0x00; - memcpy(&cmd[4], ddf->buffer, 256); - err = flashio(ddf->fd, cmd, 260, NULL, 0); - if (err < 0) - break; - - while(1) { - cmd[0] = 0x05; // RDRS - err = flashio(ddf->fd, cmd,1, &cmd[0], 1); - if (err < 0) - break; - if ((cmd[0] & 0x01) == 0) - break; - } - if (err < 0) - break; - - } - if (err < 0) - break; - - cmd[0] = 0x50; // EWSR - err = flashio(ddf->fd, cmd, 1, NULL, 0); - if (err < 0) - break; - - cmd[0] = 0x01; // WRSR - cmd[1] = LockBits; // BPx = 0, Lock all blocks - err = flashio(ddf->fd, cmd, 2, NULL, 0); - } while(0); - return err; -} - - -static int flashwrite_SSTI(struct ddflash *ddf, int fs, uint32_t FlashOffset, uint32_t maxlen, uint32_t fw_off) -{ - int err = 0; - uint8_t cmd[6]; - int i, j; - uint32_t flen, blen; - - blen = flen = lseek(fs, 0, SEEK_END) - fw_off; - if (blen % 0xfff) - blen = (blen + 0xfff) & 0xfffff000; - printf("blen = %u, flen = %u\n", blen, flen); - do { -#if 1 - cmd[0] = 0x50; // EWSR - err = flashio(ddf->fd, cmd, 1, NULL, 0); - if (err < 0) - break; - - cmd[0] = 0x01; // WRSR - cmd[1] = 0x00; // BPx = 0, Unlock all blocks - err = flashio(ddf->fd, cmd, 2, NULL, 0); - if (err < 0 ) - break; - - for (i = 0; i < flen; i += 4096) { - if ((i & 0xFFFF) == 0 ) - printf("Erase %08x\n", FlashOffset + i); - cmd[0] = 0x06; // WREN - err = flashio(ddf->fd, cmd, 1, NULL, 0); - if (err < 0 ) - break; - - cmd[0] = 0x20; // Sector erase ( 4Kb) - cmd[1] = (((FlashOffset + i ) >> 16) & 0xFF); - cmd[2] = (((FlashOffset + i ) >> 8) & 0xFF); - cmd[3] = 0x00; - err = flashio(ddf->fd,cmd,4,NULL,0); - if (err < 0 ) - break; - - while(1) { - cmd[0] = 0x05; // RDRS - err = flashio(ddf->fd,cmd,1,&cmd[0],1); - if (err < 0 ) break; - if ((cmd[0] & 0x01) == 0 ) break; - } - if (err < 0 ) break; - } - if (err < 0 ) - break; -#endif - for (j = blen - 4096; j >= 0; j -= 4096 ) { - uint32_t len = 4096; - ssize_t rlen; - - if (lseek(fs, j + fw_off, SEEK_SET) < 0) { - printf("seek error\n"); - return -1; - } - if (flen - j < 4096) { - len = flen - j; - memset(ddf->buffer, 0xff, 4096); - } - rlen = read(fs, ddf->buffer, len); - if (rlen < 0 || rlen != len) { - printf("file read error %d,%d at %u\n", rlen, errno, j); - return -1; - } - printf ("write %u bytes at %08x\n", len, j); - - if ((j & 0xFFFF) == 0 ) - printf(" Program %08x\n",FlashOffset + j); -#if 1 - for (i = 0; i < 4096; i += 2) { - if (i == 0) { - cmd[0] = 0x06; // WREN - err = flashio(ddf->fd, cmd, 1, NULL, 0); - if (err < 0 ) - break; - - cmd[0] = 0xAD; // AAI - cmd[1] = ((( FlashOffset + j ) >> 16) & 0xFF ); - cmd[2] = ((( FlashOffset + j ) >> 8) & 0xFF ); - cmd[3] = 0x00; - cmd[4] = ddf->buffer[i]; - cmd[5] = ddf->buffer[i + 1]; - err = flashio(ddf->fd,cmd,6,NULL,0); - } else { - cmd[0] = 0xAD; // AAI - cmd[1] = ddf->buffer[i]; - cmd[2] = ddf->buffer[i + 1]; - err = flashio(ddf->fd,cmd,3,NULL,0); - } - if (err < 0 ) - break; - - while(1) { - cmd[0] = 0x05; // RDRS - err = flashio(ddf->fd,cmd,1,&cmd[0],1); - if (err < 0 ) break; - if ((cmd[0] & 0x01) == 0 ) break; - } - if (err < 0 ) - break; - } - if (err < 0) - break; - - cmd[0] = 0x04; // WDIS - err = flashio(ddf->fd, cmd, 1, NULL, 0); - if (err < 0 ) - break; -#endif - } - if (err < 0 ) break; - - cmd[0] = 0x50; // EWSR - err = flashio(ddf->fd,cmd,1,NULL,0); - if (err < 0 ) break; - - cmd[0] = 0x01; // WRSR - cmd[1] = 0x1C; // BPx = 0, Lock all blocks - err = flashio(ddf->fd,cmd,2,NULL,0); - } while(0); - return err; -} - - -static int flashwrite(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, uint32_t fw_off) -{ - switch (ddf->flash_type) { - case SSTI_SST25VF016B: - case SSTI_SST25VF032B: - return flashwrite_SSTI(ddf, fs, addr, maxlen, fw_off); - case SSTI_SST25VF064C: - return flashwrite_pagemode(ddf, fs, addr, 0x3c, fw_off); - case SPANSION_S25FL116K: - case SPANSION_S25FL132K: - case SPANSION_S25FL164K: - return flashwrite_pagemode(ddf, fs, addr, 0x1c, fw_off); - } - return -1; -} - -static int flashcmp(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, uint32_t fw_off) -{ - off_t off; - uint32_t len; - int i, j, rlen; - uint8_t buf[256], buf2[256]; - int bl = sizeof(buf); - - off = lseek(fs, 0, SEEK_END); - if (off < 0) - return -1; - len = off - fw_off; - lseek(fs, fw_off, SEEK_SET); - if (len > maxlen) { - printf("file too big\n"); - return -1; - } - printf("flash file len %u, compare to %08x in flash\n", len, addr); - for (j = 0; j < len; j += bl, addr += bl) { - if (len - j < bl) - bl = len - j; - flashread(ddf->fd, buf, addr, bl); - rlen = read(fs, buf2, bl); - if (rlen < 0 || rlen != bl) { - printf("read error\n"); - return -1; - } - - if (memcmp(buf, buf2, bl)) { - printf("flash differs at %08x (offset %u)\n", addr, j); - dump(buf, 32); - dump(buf2, 32); - return addr; - } - } - printf("flash same as file\n"); - return -2; -} - - -static int flash_detect(struct ddflash *ddf) -{ - uint8_t cmd = 0x9F; - uint8_t id[3]; - - int r = flashio(ddf->fd, &cmd, 1, id, 3); - if (r < 0) - return r; - - if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x41) { - ddf->flash_type = SSTI_SST25VF016B; - printf("Flash: SSTI SST25VF016B 16 MBit\n"); - ddf->sector_size = 4096; - ddf->size = 0x200000; - } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4A) { - ddf->flash_type = SSTI_SST25VF032B; - printf("Flash: SSTI SST25VF032B 32 MBit\n"); - ddf->sector_size = 4096; - ddf->size = 0x400000; - } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4B) { - ddf->flash_type = SSTI_SST25VF064C; - printf("Flash: SSTI SST25VF064C 64 MBit\n"); - ddf->sector_size = 4096; - ddf->size = 0x800000; - } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x15) { - ddf->flash_type = SPANSION_S25FL116K; - printf("Flash: SPANSION S25FL116K 16 MBit\n"); - ddf->sector_size = 4096; - ddf->size = 0x200000; - } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x16) { - ddf->flash_type = SPANSION_S25FL132K; - printf("Flash: SPANSION S25FL132K 32 MBit\n"); - ddf->sector_size = 4096; - ddf->size = 0x400000; - } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x17) { - ddf->flash_type = SPANSION_S25FL164K; - printf("Flash: SPANSION S25FL164K 64 MBit\n"); - ddf->sector_size = 4096; - ddf->size = 0x800000; - } else if (id[0] == 0x1F && id[1] == 0x28) { - ddf->flash_type = ATMEL_AT45DB642D; - printf("Flash: Atmel AT45DB642D 64 MBit\n"); - ddf->sector_size = 1024; - ddf->size = 0x800000; - } else { - printf("Unknown Flash Flash ID = %02x %02x %02x\n", id[0], id[1], id[2]); - return -1; - } - if (ddf->sector_size) { - ddf->buffer = malloc(ddf->sector_size); - //printf("allocated buffer %08x@%08x\n", ddf->sector_size, (uint32_t) ddf->buffer); - if (!ddf->buffer) - return -1; - } - return 0; -} - - -static int get_id(struct ddflash *ddf) { - uint8_t id[4]; - - if (ioctl(ddf->fd, IOCTL_DDB_ID, &ddf->id) < 0) - return -1; -#if 1 - printf("%04x %04x %04x %04x %08x %08x\n", - ddf->id.vendor, ddf->id.device, - ddf->id.subvendor, ddf->id.subdevice, - ddf->id.hw, ddf->id.regmap); -#endif - return 0; -} - -static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off) -{ - int fd, fsize, ret = 0; - off_t off; - uint32_t p, i; - uint8_t *buf; - uint8_t hdr[256]; - unsigned int devid, version, length; - unsigned int cid[8]; - int cids = 0; - uint32_t maxlen = 1024 * 1024; - - fd = open(fn, O_RDONLY); - if (fd < 0) { - printf("%s: not found\n", fn); - return -1; - } - off = lseek(fd, 0, SEEK_END); - if (off < 0) - return -1; - fsize = off; - if (fsize > maxlen) { - close(fd); - return -1; - } - lseek(fd, 0, SEEK_SET); - buf = malloc(fsize); - if (!buf) - return -1; - read(fd, buf, fsize); - close(fd); - - for (p = 0; p < fsize && buf[p]; p++) { - char *key = &buf[p], *val = NULL; - - for (; p < fsize && buf[p] != 0x0a; p++) { - if (buf[p] == ':') { - buf[p] = 0; - val = &buf[p + 1]; - } - } - if (val == NULL || p == fsize) - break; - buf[p] = 0; - //printf("%-20s:%s\n", key, val); - if (!strcasecmp(key, "Devid")) { - sscanf(val, "%x", &devid); - } else if (!strcasecmp(key, "Compat")) { - cids = sscanf(val, "%x,%x,%x,%x,%x,%x,%x,%x", - &cid[0], &cid[1], &cid[2], &cid[3], - &cid[4], &cid[5], &cid[6], &cid[7]); - if (cids < 1) - break; - for (i = 0; i < cids; i++) - if (cid[i] == ddf->id.device) - break; - if (i == cids) { - printf("%s: no compatible id\n", fn); - ret = -2; /* no compatible ID */ - goto out; - } - } else if (!strcasecmp(key, "Version")) { - if (strchr(val,'.')) { - int major = 0, minor = 0; - sscanf(val,"%d.%d",&major,&minor); - version = (major << 16) + minor; - } else - sscanf(val, "%x", &version); - } else if (!strcasecmp(key, "Length")) { - sscanf(val, "%u", &length); - } - } - p++; - *fw_off = p; - printf("devid = %04x\n", devid); - printf("version = %08x %08x\n", version, ddf->id.hw); - printf("length = %u\n", length); - printf("fsize = %u, p = %u, f-p = %u\n", fsize, p, fsize - p); - if (devid == ddf->id.device) { - if (version <= (ddf->id.hw & 0xffffff)) { - printf("%s: old version\n", fn); - ret = -3; /* same id but no newer version */ - } - } else - ret = 1; - -out: - free(buf); - printf("check_fw = %d\n", ret); - return ret; - -} - -static int update_image(struct ddflash *ddf, char *fn, - uint32_t adr, uint32_t len, - int has_header, int no_change) -{ - int fs, res = 0; - uint32_t fw_off = 0; - - printf("Check %s\n", fn); - if (has_header) { - int ck; - - ck = check_fw(ddf, fn, &fw_off); - if (ck < 0) - return ck; - if (ck == 1 && no_change) - return 0; - } - fs = open(fn, O_RDONLY); - if (fs < 0 ) { - printf("File %s not found \n", fn); - return -1; - } - res = flashcmp(ddf, fs, adr, len, fw_off); - if (res == -2) { - printf("%s: same as flash\n", fn); - } - if (res < 0) - goto out; - res = flashwrite(ddf, fs, adr, len, fw_off); - if (res == 0) { - res = flashcmp(ddf, fs, adr, len, fw_off); - if (res == -2) { - res = 1; - } - } - -out: - close(fs); - return res; -} - - -static int fexists(char *fn) -{ - struct stat b; - - return (!stat(fn, &b)); -} static int update_flash(struct ddflash *ddf) { @@ -730,6 +197,7 @@ int main(int argc, char **argv) return -1; } } + ddf.link = 0; flash = flash_detect(&ddf); if (flash < 0) return -1; diff --git a/apps/octonet/ddtest.c b/apps/octonet/ddtest.c index fd5efe9..ba8e9fe 100644 --- a/apps/octonet/ddtest.c +++ b/apps/octonet/ddtest.c @@ -10,8 +10,10 @@ #include #include #include +#include #include "flash.h" +#include "flash.c" typedef int (*COMMAND_FUNCTION)(int dev, int argc, char* argv[], uint32_t Flags); @@ -108,12 +110,12 @@ int FlashChipEraseAtmel(int dev) Cmd[1] = ( (( i ) >> 16) & 0xFF ); Cmd[2] = ( (( i ) >> 8) & 0xFF ); Cmd[3] = 0x00; - err = flashio(dev,Cmd,4,NULL,0); + err = flashio(dev,linknr, Cmd,4,NULL,0); if( err < 0 ) break; while (1) { Cmd[0] = 0xD7; // Read Status register - err = flashio(dev,Cmd,1,&Cmd[0],1); + err = flashio(dev,linknr, Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x80) == 0x80 ) break; } @@ -131,25 +133,25 @@ int FlashChipEraseSSTI(int dev) do { Cmd[0] = 0x50; // EWSR - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev, linknr, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x01; // WRSR Cmd[1] = 0x00; // BPx = 0, Unlock all blocks - err = flashio(dev,Cmd,2,NULL,0); + err = flashio(dev, linknr, Cmd,2,NULL,0); if( err < 0 ) break; Cmd[0] = 0x06; // WREN - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev, linknr, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x60; // CHIP Erase - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev, linknr, Cmd,1,NULL,0); if( err < 0 ) break; while(1) { Cmd[0] = 0x05; // RDRS - err = flashio(dev,Cmd,1,&Cmd[0],1); + err = flashio(dev, linknr, Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x01) == 0 ) break; } @@ -157,12 +159,12 @@ int FlashChipEraseSSTI(int dev) break; Cmd[0] = 0x50; // EWSR - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev, linknr, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x01; // WRSR Cmd[1] = 0x1C; // BPx = 0, Lock all blocks - err = flashio(dev,Cmd,2,NULL,0); + err = flashio(dev, linknr, Cmd,2,NULL,0); } while(0); @@ -332,7 +334,7 @@ int flashioc(int dev,int argc, char* argv[],uint32_t Flags) Buffer[i] = (uint8_t) tmp; } - if( flashio(dev,Buffer,WriteLen,Buffer,ReadLen) < 0 ) + if( flashio(dev, linknr, Buffer,WriteLen,Buffer,ReadLen) < 0 ) { return 0; } @@ -1289,7 +1291,7 @@ static int read_sfpd(int dev, uint8_t adr, uint8_t *val) uint8_t cmd[5] = { 0x5a, 0, 0, adr, 0 }; int r; - r = flashio(dev, cmd, 5, val, 1); + r = flashio(dev, linknr, cmd, 5, val, 1); if (r < 0) return r; return 0; @@ -1301,7 +1303,7 @@ static int read_sst_id(int dev, uint8_t *id) uint8_t buf[9]; int r; - r = flashio(dev, cmd, 2, buf, 9); + r = flashio(dev, linknr, cmd, 2, buf, 9); if (r < 0) return r; memcpy(id, buf + 1, 8); @@ -1313,7 +1315,7 @@ static int read_winbd(int dev, uint8_t *val) uint8_t cmd[5] = { 0x4b, 0, 0, 0, 0 }; int r; - r = flashio(dev, cmd, 5, val, 8); + r = flashio(dev, linknr, cmd, 5, val, 8); if (r < 0) return r; return 0; diff --git a/apps/octonet/ddupdate.c b/apps/octonet/ddupdate.c new file mode 100644 index 0000000..71596b2 --- /dev/null +++ b/apps/octonet/ddupdate.c @@ -0,0 +1,245 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#include "flash.h" +#include "flash.c" + +static int verbose = 0; + + +static int update_flash(struct ddflash *ddf) +{ + char *fname; + int res, stat = 0; + char *name; + + switch (ddf->id.device) { + case 0x300: + case 0x301: + case 0x302: + case 0x307: + if ((res = update_image(ddf, "/boot/bs.img", 0x4000, 0x1000, 0, 0)) == 1) + stat |= 4; + if ((res = update_image(ddf, "/boot/uboot.img", 0xb0000, 0xb0000, 0, 0)) == 1) + stat |= 2; + if (fexists("/config/gtl.enabled")) { + if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x10000, 0xa0000, 1, 0)) == 1) + stat |= 1; + if (res == -1) + if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x10000, 0xa0000, 1, 0)) == 1) + stat |= 1; + } else if (fexists("/config/gtl.disabled")) { + if ((res = update_image(ddf, "/config/fpga.img", 0x10000, 0xa0000, 1, 0)) == 1) + stat |= 1; + if (res == -1) + if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 0)) == 1) + stat |= 1; + } else { + if (ddf->id.device == 0x0307) { + if (res == -1) + if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1) + stat |= 1; + if (res == -1) + if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x10000, 0xa0000, 1, 1)) == 1) + stat |= 1; + } else { + if ((res = update_image(ddf, "/config/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1) + stat |= 1; + if (res == -1) + if ((res = update_image(ddf, "/boot/fpga.img", 0x10000, 0xa0000, 1, 1)) == 1) + stat |= 1; + } + } +#if 1 + if ( (stat&1) && (ddf->id.hw & 0xffffff) <= 0x010001) { + if (ddf->id.device == 0x0307) { + if ((res = update_image(ddf, "/config/fpga_gtl.img", 0x160000, 0x80000, 1, 0)) == 1) + stat |= 1; + if (res == -1) + if ((res = update_image(ddf, "/boot/fpga_gtl.img", 0x160000, 0x80000, 1, 0)) == 1) + stat |= 1; + } else { + if ((res = update_image(ddf, "/config/fpga.img", 0x160000, 0x80000, 1, 0)) == 1) + stat |= 1; + if (res == -1) + if ((res = update_image(ddf, "/boot/fpga.img", 0x160000, 0x80000, 1, 0)) == 1) + stat |= 1; + + } + } +#endif + + break; + case 0x320: + //fname="/boot/DVBNetV1A_DD01_0300.bit"; + fname="/boot/fpga.img"; + if ((res = update_image(ddf, fname, 0x10000, 0x100000, 1, 0)) == 1) + stat |= 1; + return stat; + break; + case 0x322: + //fname="/boot/DVBNetV1A_DD01_0300.bit"; + fname="/boot/fpga.img"; + if ((res = update_image(ddf, fname, 0x10000, 0x100000, 1, 0)) == 1) + stat |= 1; + return stat; + break; + default: + fname = ddf->fname; + if (!fname) + fname = devid2fname(ddf->id.device, &name); + if (name) + printf("Card: %s\n", name); + if ((res = update_image(ddf, fname, 0x10000, 0x100000, 1, 0)) == 1) + stat |= 1; + return stat; + } + return stat; +} + +static int ddupdate(struct ddflash *ddf) +{ + int ret; + + if (verbose >= 2) + printf("Detect flash type\n"); + ret = flash_detect(ddf); + if (ret < 0) + return ret; + ret = update_flash(ddf); + + if (ddf->buffer) + free(ddf->buffer); + + return ret; +} + +static int proc_card(int ddbnum, char *fname) +{ + struct ddflash ddf; + char ddbname[80]; + struct ddb_id ddbid; + int ddb, ret, link, links; + + sprintf(ddbname, "/dev/ddbridge/card%d", ddbnum); + if (verbose >= 2) + printf("Update card %s\n", ddbname); + ddb = open(ddbname, O_RDWR); + if (ddb < 0) + return -3; + ddf.fd = ddb; + ddf.link = 0; + ddf.fname = fname; + links = 1; + + for (link = 0; link < links; link++) { + ddf.link = link; + if (verbose >= 2) + printf("Get id card %u link %u\n", ddbnum, link); + ret = get_id(&ddf); + if (ret < 0) + goto out; + if (!link) { + switch (ddf.id.device) { + case 0x20: + links = 4; + break; + case 0x300: + case 0x301: + case 0x307: + links = 1; + break; + + default: + break; + } + } + + //printf("%08x %08x\n", ddf.id.device, ddf.id.subdevice); + if (ddf.id.device) { + ret = ddupdate(&ddf); + if (ret < 0) + break; + } + } + +out: + close(ddb); + return ret; +} + + +int main(int argc, char **argv) +{ + int ddbnum = 0, all = 0, i, force = 0; + char *fname; + + while (1) { + int option_index = 0; + int c; + static struct option long_options[] = { + {"help", no_argument , NULL, 'h'}, + {0, 0, 0, 0} + }; + c = getopt_long(argc, argv, + "n:havfb:", + long_options, &option_index); + if (c==-1) + break; + + switch (c) { + case 'b': + fname = optarg; + break; + case 'n': + ddbnum = strtol(optarg, NULL, 0); + break; + case 'a': + all = 1; + break; + case 'v': + verbose++; + break; + case 'h': + printf("ddupdate [OPTION]\n\n" + "-n N\n only update card N (default with N=0)\n\n" + "-a \n update all cards\n\n" + "-b file\n fpga image file override (not if -a is used)\n\n" + "-v \n more verbose (up to -v -v -v)\n\n" + ); + break; + default: + break; + + } + } + if (optind < argc) { + printf("Warning: unused arguments\n"); + } + + if (!all) + return proc_card(ddbnum, fname); + + for (i = 0; i < 20; i++) { + int ret = proc_card(i, 0); + + if (ret == -3) /* could not open, no more cards! */ + break; + if (ret < 0) + return i; /* fatal error */ + if (verbose >= 1) + printf("card %d up to date\n", i); + } + return 0; +} diff --git a/apps/octonet/flash.c b/apps/octonet/flash.c index 82621d7..b8f2234 100644 --- a/apps/octonet/flash.c +++ b/apps/octonet/flash.c @@ -1,25 +1,14 @@ -enum { - UNKNOWN_FLASH = 0, - ATMEL_AT45DB642D = 1, - SSTI_SST25VF016B = 2, - SSTI_SST25VF032B = 3, - SSTI_SST25VF064C = 4, - SPANSION_S25FL116K = 5, - SPANSION_S25FL132K = 6, - SPANSION_S25FL164K = 7, - WINBOND_W25Q16JV = 8, -}; - static uint32_t linknr = 0; -int flashio(int ddb, uint8_t *wbuf, uint32_t wlen, uint8_t *rbuf, uint32_t rlen) +int flashio(int ddb, int link, + uint8_t *wbuf, uint32_t wlen, uint8_t *rbuf, uint32_t rlen) { struct ddb_flashio fio = { .write_buf=wbuf, .write_len=wlen, .read_buf=rbuf, .read_len=rlen, - .link=linknr, + .link=link, }; return ioctl(ddb, IOCTL_DDB_FLASHIO, &fio); @@ -30,7 +19,7 @@ int FlashDetect(int dev) uint8_t Cmd = 0x9F; uint8_t Id[3]; - int r = flashio(dev, &Cmd, 1, Id, 3); + int r = flashio(dev, linknr, &Cmd, 1, Id, 3); if (r < 0) return r; @@ -92,7 +81,7 @@ static int flashdetect(int fd, uint32_t *sector_size, uint32_t *flash_size) uint8_t id[3]; int flash_type; - int r = flashio(fd, &cmd, 1, id, 3); + int r = flashio(fd, linknr, &cmd, 1, id, 3); if (r < 0) return r; @@ -161,7 +150,7 @@ int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len) l = 1024; else l = len; - ret = flashio(ddb, cmd, 4, buf, l); + ret = flashio(ddb, linknr, cmd, 4, buf, l); if (ret < 0) return ret; addr += l; @@ -176,7 +165,7 @@ static int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len) uint8_t cmd[4]= {0x03, (addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff}; - return flashio(ddb, cmd, 4, buf, len); + return flashio(ddb, linknr, cmd, 4, buf, len); } #endif @@ -273,13 +262,13 @@ int FlashWriteAtmel(int dev,uint32_t FlashOffset, uint8_t *Buffer,int BufferSize Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF ); Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF ); Cmd[3] = 0x00; - err = flashio(dev,Cmd,4,NULL,0); + err = flashio(dev,linknr, Cmd,4,NULL,0); if( err < 0 ) break; while( 1 ) { Cmd[0] = 0xD7; // Read Status register - err = flashio(dev,Cmd,1,&Cmd[0],1); + err = flashio(dev,linknr, Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x80) == 0x80 ) break; } @@ -299,7 +288,7 @@ int FlashWriteAtmel(int dev,uint32_t FlashOffset, uint8_t *Buffer,int BufferSize Cmd[3] = 0x00; memcpy(&Cmd[4],&Buffer[i],1024); - err = flashio(dev,Cmd,4 + 1024,NULL,0); + err = flashio(dev,linknr, Cmd,4 + 1024,NULL,0); if( err < 0 ) break; Cmd[0] = BlockErase ? 0x88 : 0x83; // Buffer to Main Memory (with Erase) @@ -307,13 +296,13 @@ int FlashWriteAtmel(int dev,uint32_t FlashOffset, uint8_t *Buffer,int BufferSize Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF ); Cmd[3] = 0x00; - err = flashio(dev,Cmd,4,NULL,0); + err = flashio(dev,linknr, Cmd,4,NULL,0); if( err < 0 ) break; while( 1 ) { Cmd[0] = 0xD7; // Read Status register - err = flashio(dev,Cmd,1,&Cmd[0],1); + err = flashio(dev,linknr, Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x80) == 0x80 ) break; } @@ -335,13 +324,13 @@ int FlashWriteSSTI(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSiz do { cmd[0] = 0x50; // EWSR - err = flashio(dev,cmd,1,NULL,0); + err = flashio(dev,linknr, cmd,1,NULL,0); if (err < 0 ) break; cmd[0] = 0x01; // WRSR cmd[1] = 0x00; // BPx = 0, Unlock all blocks - err = flashio(dev,cmd,2,NULL,0); + err = flashio(dev,linknr, cmd,2,NULL,0); if (err < 0 ) break; @@ -349,7 +338,7 @@ int FlashWriteSSTI(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSiz if ((i & 0xFFFF) == 0 ) printf(" Erase %08x\n",FlashOffset + i); cmd[0] = 0x06; // WREN - err = flashio(dev,cmd,1,NULL,0); + err = flashio(dev,linknr, cmd,1,NULL,0); if (err < 0 ) break; @@ -357,13 +346,13 @@ int FlashWriteSSTI(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSiz cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF ); cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF ); cmd[3] = 0x00; - err = flashio(dev,cmd,4,NULL,0); + err = flashio(dev,linknr, cmd,4,NULL,0); if (err < 0 ) break; while(1) { cmd[0] = 0x05; // RDRS - err = flashio(dev,cmd,1,&cmd[0],1); + err = flashio(dev,linknr, cmd,1,&cmd[0],1); if (err < 0 ) break; if ((cmd[0] & 0x01) == 0 ) break; } @@ -378,7 +367,7 @@ int FlashWriteSSTI(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSiz for (i = 0; i < 4096; i += 2 ) { if (i == 0 ) { cmd[0] = 0x06; // WREN - err = flashio(dev,cmd,1,NULL,0); + err = flashio(dev,linknr, cmd,1,NULL,0); if (err < 0 ) break; @@ -388,19 +377,19 @@ int FlashWriteSSTI(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSiz cmd[3] = 0x00; cmd[4] = Buffer[j+i]; cmd[5] = Buffer[j+i+1]; - err = flashio(dev,cmd,6,NULL,0); + err = flashio(dev,linknr, cmd,6,NULL,0); } else { cmd[0] = 0xAD; // AAI cmd[1] = Buffer[j+i]; cmd[2] = Buffer[j+i+1]; - err = flashio(dev,cmd,3,NULL,0); + err = flashio(dev,linknr, cmd,3,NULL,0); } if (err < 0 ) break; while(1) { cmd[0] = 0x05; // RDRS - err = flashio(dev,cmd,1,&cmd[0],1); + err = flashio(dev,linknr, cmd,1,&cmd[0],1); if (err < 0 ) break; if ((cmd[0] & 0x01) == 0 ) break; } @@ -409,19 +398,19 @@ int FlashWriteSSTI(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferSiz if (err < 0 ) break; cmd[0] = 0x04; // WDIS - err = flashio(dev,cmd,1,NULL,0); + err = flashio(dev,linknr, cmd,1,NULL,0); if (err < 0 ) break; } if (err < 0 ) break; cmd[0] = 0x50; // EWSR - err = flashio(dev,cmd,1,NULL,0); + err = flashio(dev,linknr, cmd,1,NULL,0); if (err < 0 ) break; cmd[0] = 0x01; // WRSR cmd[1] = 0x1C; // BPx = 0, Lock all blocks - err = flashio(dev,cmd,2,NULL,0); + err = flashio(dev,linknr, cmd,2,NULL,0); } while(0); return err; } @@ -438,13 +427,13 @@ int FlashWriteSSTI_B(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferS do { Cmd[0] = 0x50; // EWSR - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev,linknr, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x01; // WRSR Cmd[1] = 0x00; // BPx = 0, Unlock all blocks - err = flashio(dev,Cmd,2,NULL,0); + err = flashio(dev,linknr, Cmd,2,NULL,0); if( err < 0 ) break; @@ -452,7 +441,7 @@ int FlashWriteSSTI_B(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferS if( (i & 0xFFFF) == 0 ) printf(" Erase %08x\n",FlashOffset + i); Cmd[0] = 0x06; // WREN - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev,linknr, Cmd,1,NULL,0); if( err < 0 ) break; @@ -460,13 +449,13 @@ int FlashWriteSSTI_B(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferS Cmd[1] = ( (( FlashOffset + i ) >> 16) & 0xFF ); Cmd[2] = ( (( FlashOffset + i ) >> 8) & 0xFF ); Cmd[3] = 0x00; - err = flashio(dev,Cmd,4,NULL,0); + err = flashio(dev,linknr, Cmd,4,NULL,0); if( err < 0 ) break; while(1) { Cmd[0] = 0x05; // RDRS - err = flashio(dev,Cmd,1,&Cmd[0],1); + err = flashio(dev,linknr, Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x01) == 0 ) break; } @@ -481,7 +470,7 @@ int FlashWriteSSTI_B(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferS for(i = 0; i < 4096; i += 2 ) { if( i == 0 ) { Cmd[0] = 0x06; // WREN - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev,linknr, Cmd,1,NULL,0); if( err < 0 ) break; @@ -491,19 +480,19 @@ int FlashWriteSSTI_B(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferS Cmd[3] = 0x00; Cmd[4] = Buffer[j+i]; Cmd[5] = Buffer[j+i+1]; - err = flashio(dev,Cmd,6,NULL,0); + err = flashio(dev,linknr, Cmd,6,NULL,0); } else { Cmd[0] = 0xAD; // AAI Cmd[1] = Buffer[j+i]; Cmd[2] = Buffer[j+i+1]; - err = flashio(dev,Cmd,3,NULL,0); + err = flashio(dev,linknr, Cmd,3,NULL,0); } if( err < 0 ) break; while(1) { Cmd[0] = 0x05; // RDRS - err = flashio(dev,Cmd,1,&Cmd[0],1); + err = flashio(dev,linknr, Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x01) == 0 ) break; } @@ -512,19 +501,19 @@ int FlashWriteSSTI_B(int dev, uint32_t FlashOffset, uint8_t *Buffer, int BufferS if( err < 0 ) break; Cmd[0] = 0x04; // WDIS - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev,linknr, Cmd,1,NULL,0); if( err < 0 ) break; } if( err < 0 ) break; Cmd[0] = 0x50; // EWSR - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev,linknr, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x01; // WRSR Cmd[1] = 0x1C; // BPx = 0, Lock all blocks - err = flashio(dev,Cmd,2,NULL,0); + err = flashio(dev,linknr, Cmd,2,NULL,0); } while(0); return err; } @@ -541,12 +530,12 @@ int FlashWritePageMode(int dev, uint32_t FlashOffset, do { Cmd[0] = 0x50; // EWSR - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev,linknr, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x01; // WRSR Cmd[1] = 0x00; // BPx = 0, Unlock all blocks - err = flashio(dev,Cmd,2,NULL,0); + err = flashio(dev,linknr, Cmd,2,NULL,0); if( err < 0 ) break; for(i = 0; i < BufferSize; i += 4096 ) @@ -557,20 +546,20 @@ int FlashWritePageMode(int dev, uint32_t FlashOffset, } Cmd[0] = 0x06; // WREN - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev,linknr, 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(dev,Cmd,4,NULL,0); + err = flashio(dev,linknr, Cmd,4,NULL,0); if( err < 0 ) break; while(1) { Cmd[0] = 0x05; // RDRS - err = flashio(dev,Cmd,1,&Cmd[0],1); + err = flashio(dev,linknr, Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x01) == 0 ) break; } @@ -588,7 +577,7 @@ int FlashWritePageMode(int dev, uint32_t FlashOffset, } Cmd[0] = 0x06; // WREN - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev,linknr, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x02; // PP @@ -596,13 +585,13 @@ int FlashWritePageMode(int dev, uint32_t FlashOffset, Cmd[2] = ( (( FlashOffset + j ) >> 8) & 0xFF ); Cmd[3] = 0x00; memcpy(&Cmd[4],&Buffer[j],256); - err = flashio(dev,Cmd,260,NULL,0); + err = flashio(dev,linknr, Cmd,260,NULL,0); if( err < 0 ) break; while(1) { Cmd[0] = 0x05; // RDRS - err = flashio(dev,Cmd,1,&Cmd[0],1); + err = flashio(dev,linknr, Cmd,1,&Cmd[0],1); if( err < 0 ) break; if( (Cmd[0] & 0x01) == 0 ) break; } @@ -612,14 +601,651 @@ int FlashWritePageMode(int dev, uint32_t FlashOffset, if( err < 0 ) break; Cmd[0] = 0x50; // EWSR - err = flashio(dev,Cmd,1,NULL,0); + err = flashio(dev,linknr, Cmd,1,NULL,0); if( err < 0 ) break; Cmd[0] = 0x01; // WRSR Cmd[1] = LockBits; // BPx = 0, Lock all blocks - err = flashio(dev,Cmd,2,NULL,0); + err = flashio(dev,linknr, Cmd,2,NULL,0); } while(0); return err; } + +int flashwrite_pagemode(struct ddflash *ddf, int dev, uint32_t FlashOffset, + uint8_t LockBits, uint32_t fw_off) +{ + int err = 0; + uint8_t cmd[260]; + int i, j; + uint32_t flen, blen; + + blen = flen = lseek(dev, 0, SEEK_END) - fw_off; + if (blen % 0xff) + blen = (blen + 0xff) & 0xffffff00; + printf("blen = %u, flen = %u\n", blen, flen); + + do { + cmd[0] = 0x50; // EWSR + err = flashio(ddf->fd, 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; + + 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; + + for (j = blen - 256; j >= 0; j -= 256 ) { + uint32_t len = 256; + ssize_t rlen; + + if (lseek(dev, j + fw_off, SEEK_SET) < 0) { + printf("seek error\n"); + return -1; + } + if (flen - j < 256) { + len = flen - j; + memset(ddf->buffer, 0xff, 256); + } + rlen = read(dev, ddf->buffer, len); + if (rlen < 0 || rlen != len) { + printf("file read error %d,%d at %u\n", rlen, errno, j); + return -1; + } + printf ("write %u bytes at %08x\n", len, j); + + + if ((j & 0xFFFF) == 0) + printf(" Programm %08x\n", FlashOffset + j); + + cmd[0] = 0x06; // WREN + err = flashio(ddf->fd, 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 + err = flashio(ddf->fd, ddf->link, cmd, 1, NULL, 0); + if (err < 0) + break; + + cmd[0] = 0x01; // WRSR + cmd[1] = LockBits; // BPx = 0, Lock all blocks + err = flashio(ddf->fd, ddf->link, cmd, 2, NULL, 0); + } while(0); + return err; +} + + +static int flashwrite_SSTI(struct ddflash *ddf, int fs, uint32_t FlashOffset, uint32_t maxlen, uint32_t fw_off) +{ + int err = 0; + uint8_t cmd[6]; + int i, j; + uint32_t flen, blen; + + blen = flen = lseek(fs, 0, SEEK_END) - fw_off; + if (blen % 0xfff) + blen = (blen + 0xfff) & 0xfffff000; + printf("blen = %u, flen = %u\n", blen, flen); + do { +#if 1 + cmd[0] = 0x50; // EWSR + err = flashio(ddf->fd, 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; + + 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; +#endif + for (j = blen - 4096; j >= 0; j -= 4096 ) { + uint32_t len = 4096; + ssize_t rlen; + + if (lseek(fs, j + fw_off, SEEK_SET) < 0) { + printf("seek error\n"); + return -1; + } + if (flen - j < 4096) { + len = flen - j; + memset(ddf->buffer, 0xff, 4096); + } + rlen = read(fs, ddf->buffer, len); + if (rlen < 0 || rlen != len) { + printf("file read error %d,%d at %u\n", rlen, errno, j); + return -1; + } + printf ("write %u bytes at %08x\n", len, j); + + if ((j & 0xFFFF) == 0 ) + printf(" Program %08x\n",FlashOffset + j); +#if 1 + for (i = 0; i < 4096; i += 2) { + if (i == 0) { + cmd[0] = 0x06; // WREN + err = flashio(ddf->fd, ddf->link, cmd, 1, NULL, 0); + if (err < 0 ) + break; + + cmd[0] = 0xAD; // AAI + cmd[1] = ((( FlashOffset + j ) >> 16) & 0xFF ); + cmd[2] = ((( FlashOffset + j ) >> 8) & 0xFF ); + cmd[3] = 0x00; + cmd[4] = ddf->buffer[i]; + cmd[5] = ddf->buffer[i + 1]; + err = flashio(ddf->fd,ddf->link, cmd,6,NULL,0); + } else { + cmd[0] = 0xAD; // AAI + cmd[1] = ddf->buffer[i]; + cmd[2] = ddf->buffer[i + 1]; + err = flashio(ddf->fd,ddf->link, cmd,3,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] = 0x04; // WDIS + err = flashio(ddf->fd, ddf->link, cmd, 1, NULL, 0); + if (err < 0 ) + break; +#endif + } + if (err < 0 ) break; + + cmd[0] = 0x50; // EWSR + err = flashio(ddf->fd,ddf->link, cmd,1,NULL,0); + if (err < 0 ) break; + + cmd[0] = 0x01; // WRSR + cmd[1] = 0x1C; // BPx = 0, Lock all blocks + err = flashio(ddf->fd,ddf->link, cmd,2,NULL,0); + } while(0); + return err; +} + + +static int flashwrite(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, uint32_t fw_off) +{ + switch (ddf->flash_type) { + case SSTI_SST25VF016B: + case SSTI_SST25VF032B: + return flashwrite_SSTI(ddf, fs, addr, maxlen, fw_off); + case SSTI_SST25VF064C: + return flashwrite_pagemode(ddf, fs, addr, 0x3c, fw_off); + case SPANSION_S25FL116K: + case SPANSION_S25FL132K: + case SPANSION_S25FL164K: + case WINBOND_W25Q16JV: + return flashwrite_pagemode(ddf, fs, addr, 0x1c, fw_off); + } + return -1; +} + + +static int flash_detect(struct ddflash *ddf) +{ + uint8_t cmd = 0x9F; + uint8_t id[3]; + + int r = flashio(ddf->fd, ddf->link, &cmd, 1, id, 3); + if (r < 0) + return r; + + if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x41) { + ddf->flash_type = SSTI_SST25VF016B; + printf("Flash: SSTI SST25VF016B 16 MBit\n"); + ddf->sector_size = 4096; + ddf->size = 0x200000; + } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4A) { + ddf->flash_type = SSTI_SST25VF032B; + printf("Flash: SSTI SST25VF032B 32 MBit\n"); + ddf->sector_size = 4096; + ddf->size = 0x400000; + } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4B) { + ddf->flash_type = SSTI_SST25VF064C; + printf("Flash: SSTI SST25VF064C 64 MBit\n"); + ddf->sector_size = 4096; + ddf->size = 0x800000; + } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x15) { + ddf->flash_type = SPANSION_S25FL116K; + printf("Flash: SPANSION S25FL116K 16 MBit\n"); + ddf->sector_size = 4096; + ddf->size = 0x200000; + } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x16) { + ddf->flash_type = SPANSION_S25FL132K; + printf("Flash: SPANSION S25FL132K 32 MBit\n"); + ddf->sector_size = 4096; + ddf->size = 0x400000; + } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x17) { + ddf->flash_type = SPANSION_S25FL164K; + printf("Flash: SPANSION S25FL164K 64 MBit\n"); + ddf->sector_size = 4096; + ddf->size = 0x800000; + } else if (id[0] == 0x1F && id[1] == 0x28) { + ddf->flash_type = ATMEL_AT45DB642D; + printf("Flash: Atmel AT45DB642D 64 MBit\n"); + ddf->sector_size = 1024; + ddf->size = 0x800000; + } else if (id[0] == 0xef && id[1] == 0x40 && id[2] == 0x15) { + ddf->flash_type = WINBOND_W25Q16JV; + printf("Flash: Winbond W25Q16JV 16 MBit\n"); + ddf->sector_size = 4096; + ddf->size = 0x200000; + } else { + printf("Unknown Flash Flash ID = %02x %02x %02x\n", id[0], id[1], id[2]); + return -1; + } + if (ddf->sector_size) { + ddf->buffer = malloc(ddf->sector_size); + //printf("allocated buffer %08x@%08x\n", ddf->sector_size, (uint32_t) ddf->buffer); + if (!ddf->buffer) + return -1; + } + return 0; +} + +static int get_id(struct ddflash *ddf) +{ + uint8_t id[4]; + struct ddb_reg ddbreg; + + if (ddf->link == 0) { + if (ioctl(ddf->fd, IOCTL_DDB_ID, &ddf->id) < 0) + return -1; + return 0; + } + ddbreg.reg = 8 + (ddf->link << 28); + if (ioctl(ddf->fd, IOCTL_DDB_READ_REG, &ddbreg) < 0) + return -1; + ddf->id.vendor = ddbreg.val; + ddf->id.device = ddbreg.val >> 16; + + ddbreg.reg = 12 + (ddf->link << 28); + if (ioctl(ddf->fd, IOCTL_DDB_READ_REG, &ddbreg) < 0) + return -1; + ddf->id.subvendor = ddbreg.val; + ddf->id.subdevice = ddbreg.val >> 16; + + ddbreg.reg = 0 + (ddf->link << 28); + if (ioctl(ddf->fd, IOCTL_DDB_READ_REG, &ddbreg) < 0) + return -1; + ddf->id.hw = ddbreg.val; + + ddbreg.reg = 4 + (ddf->link << 28); + if (ioctl(ddf->fd, IOCTL_DDB_READ_REG, &ddbreg) < 0) + return -1; + ddf->id.regmap = ddbreg.val; + return 0; +} + + +static char *devid2fname(uint16_t devid, char **name) +{ + char *fname = 0; + + switch (devid) { + case 0x0002: + fname="DVBBridgeV1A_DVBBridgeV1A.bit"; + *name = "Octopus 35\n"; + break; + case 0x0003: + fname="DVBBridgeV1B_DVBBridgeV1B.fpga"; + *name = "Octopus\n"; + break; + case 0x0005: + fname="DVBBridgeV2A_DD01_0005_STD.fpga"; + *name = "Octopus Classic\n"; + break; + case 0x0006: + fname="DVBBridgeV2A_DD01_0006_STD.fpga"; + *name = "CineS2 V7\n"; + break; + case 0x0007: + fname="DVBBridgeV2A_DD01_0007_MXL.fpga"; + *name = "Octopus 4/8\n"; + break; + case 0x0008: + fname="DVBBridgeV2A_DD01_0008_CXD.fpga"; + *name = "Octopus 4/8\n"; + break; + case 0x0009: + fname="DVBBridgeV2A_DD01_0009_SX8.fpga"; + *name = "Octopus MAXSX8\n"; + break; + case 0x000b: + fname="DVBBridgeV2A_DD01_000B_SX8.fpga"; + *name = "Octopus MAXSX8 Basic\n"; + break; + case 0x000a: + fname="DVBBridgeV2A_DD01_000A_M4.fpga"; + *name = "Octopus MAXM4\n"; + break; + case 0x0011: + fname="DVBBridgeV2B_DD01_0011.fpga"; + *name = "Octopus CI\n"; + break; + case 0x0012: + fname="DVBBridgeV2B_DD01_0012_STD.fpga"; + *name = "Octopus CI\n"; + break; + case 0x0013: + fname="DVBBridgeV2B_DD01_0013_PRO.fpga"; + *name = "Octopus PRO\n"; + break; + case 0x0020: + fname="DVBBridgeV2C_DD01_0020.fpga"; + *name = "Octopus GT Mini\n"; + break; + case 0x0201: + fname="DVBModulatorV1B_DVBModulatorV1B.bit"; + *name = "Modulator\n"; + break; + case 0x0203: + fname="DVBModulatorV1B_DD01_0203.fpga"; + *name = "Modulator Test\n"; + break; + case 0x0210: + fname="DVBModulatorV2A_DD01_0210.fpga"; + *name = "Modulator V2\n"; + break; + case 0x0220: + fname="SDRModulatorV1A_DD01_0220.fpga"; + *name = "SDRModulator ATV\n"; + break; + case 0x0221: + fname="SDRModulatorV1A_DD01_0221_IQ.fpga"; + *name = "SDRModulator IQ\n"; + break; + case 0x0222: + fname="SDRModulatorV1A_DD01_0222_DVBT.fpga"; + *name = "SDRModulator DVBT\n"; + break; + default: + *name = "UNKNOWN\n"; + break; + } + return fname; +} + + + +static int flashcmp(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, uint32_t fw_off) +{ + off_t off; + uint32_t len; + int i, j, rlen; + uint8_t buf[256], buf2[256]; + int bl = sizeof(buf); + + off = lseek(fs, 0, SEEK_END); + if (off < 0) + return -1; + len = off - fw_off; + lseek(fs, fw_off, SEEK_SET); + if (len > maxlen) { + printf("file too big\n"); + return -1; + } + printf("flash file len %u, compare to %08x in flash\n", len, addr); + for (j = 0; j < len; j += bl, addr += bl) { + if (len - j < bl) + bl = len - j; + flashread(ddf->fd, buf, addr, bl); + rlen = read(fs, buf2, bl); + if (rlen < 0 || rlen != bl) { + printf("read error\n"); + return -1; + } + + if (memcmp(buf, buf2, bl)) { + printf("flash differs at %08x (offset %u)\n", addr, j); + dump(buf, 32); + dump(buf2, 32); + return addr; + } + } + printf("flash same as file\n"); + return -2; +} + +static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off) +{ + int fd, fsize, ret = 0; + off_t off; + uint32_t p, i; + uint8_t *buf; + uint8_t hdr[256]; + unsigned int devid, version, length; + unsigned int cid[8]; + int cids = 0; + uint32_t maxlen = 1024 * 1024; + + fd = open(fn, O_RDONLY); + if (fd < 0) { + printf("%s: not found\n", fn); + return -1; + } + off = lseek(fd, 0, SEEK_END); + if (off < 0) + return -1; + fsize = off; + if (fsize > maxlen) { + close(fd); + return -1; + } + lseek(fd, 0, SEEK_SET); + buf = malloc(fsize); + if (!buf) + return -1; + read(fd, buf, fsize); + close(fd); + + for (p = 0; p < fsize && buf[p]; p++) { + char *key = &buf[p], *val = NULL; + + for (; p < fsize && buf[p] != 0x0a; p++) { + if (buf[p] == ':') { + buf[p] = 0; + val = &buf[p + 1]; + } + } + if (val == NULL || p == fsize) + break; + buf[p] = 0; + //printf("%-20s:%s\n", key, val); + if (!strcasecmp(key, "Devid")) { + sscanf(val, "%x", &devid); + } else if (!strcasecmp(key, "Compat")) { + cids = sscanf(val, "%x,%x,%x,%x,%x,%x,%x,%x", + &cid[0], &cid[1], &cid[2], &cid[3], + &cid[4], &cid[5], &cid[6], &cid[7]); + if (cids < 1) + break; + for (i = 0; i < cids; i++) + if (cid[i] == ddf->id.device) + break; + if (i == cids) { + printf("%s: no compatible id found\n", fn); + ret = -2; /* no compatible ID */ + goto out; + } + } else if (!strcasecmp(key, "Version")) { + if (strchr(val,'.')) { + int major = 0, minor = 0; + sscanf(val,"%d.%d",&major,&minor); + version = (major << 16) + minor; + } else + sscanf(val, "%x", &version); + } else if (!strcasecmp(key, "Length")) { + sscanf(val, "%u", &length); + } + } + p++; + *fw_off = p; + printf("devid = %04x\n", devid); + printf("version = %08x %08x\n", version, ddf->id.hw); + printf("length = %u\n", length); + printf("fsize = %u, p = %u, f-p = %u\n", fsize, p, fsize - p); + if (devid == ddf->id.device) { + if (version <= (ddf->id.hw & 0xffffff)) { + printf("%s: older or same version\n", fn); + ret = -3; /* same id but no newer version */ + } + } else + ret = 1; + +out: + free(buf); + printf("check_fw = %d\n", ret); + return ret; + +} + +static int update_image(struct ddflash *ddf, char *fn, + uint32_t adr, uint32_t len, + int has_header, int no_change) +{ + int fs, res = 0; + uint32_t fw_off = 0; + + printf("Check %s\n", fn); + if (has_header) { + int ck; + + ck = check_fw(ddf, fn, &fw_off); + if (ck < 0) + return ck; + if (ck == 1 && no_change) + return 0; + } + fs = open(fn, O_RDONLY); + if (fs < 0 ) { + printf("File %s not found \n", fn); + return -1; + } + res = flashcmp(ddf, fs, adr, len, fw_off); + if (res == -2) { + printf("%s: same as flash\n", fn); + } + if (res < 0) + goto out; + res = flashwrite(ddf, fs, adr, len, fw_off); + if (res == 0) { + res = flashcmp(ddf, fs, adr, len, fw_off); + if (res == -2) { + res = 1; + } + } + +out: + close(fs); + return res; +} + + +static int fexists(char *fn) +{ + struct stat b; + + return (!stat(fn, &b)); +} + diff --git a/apps/octonet/flash.h b/apps/octonet/flash.h index 3b8c4c2..60c5235 100644 --- a/apps/octonet/flash.h +++ b/apps/octonet/flash.h @@ -62,4 +62,33 @@ struct ddb_i2c_msg { #define IOCTL_DDB_READ_I2C _IOWR(DDB_MAGIC, 0x0a, struct ddb_i2c_msg) #define IOCTL_DDB_WRITE_I2C _IOR(DDB_MAGIC, 0x0b, struct ddb_i2c_msg) -#include "flash.c" +enum { + UNKNOWN_FLASH = 0, + ATMEL_AT45DB642D = 1, + SSTI_SST25VF016B = 2, + SSTI_SST25VF032B = 3, + SSTI_SST25VF064C = 4, + SPANSION_S25FL116K = 5, + SPANSION_S25FL132K = 6, + SPANSION_S25FL164K = 7, + WINBOND_W25Q16JV = 8, +}; + +struct ddflash { + int fd; + uint32_t link; + char *fname; + + struct ddb_id id; + uint32_t version; + + uint32_t flash_type; + uint32_t sector_size; + uint32_t size; + + uint32_t bufsize; + uint32_t block_erase; + + uint8_t *buffer; +}; + From 5b17d3280438d703e53da42de5139915f7604926 Mon Sep 17 00:00:00 2001 From: rjkm Date: Sat, 18 Jan 2020 16:36:16 +0100 Subject: [PATCH 15/55] init fname --- apps/octonet/ddupdate.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/octonet/ddupdate.c b/apps/octonet/ddupdate.c index 71596b2..a3d4f26 100644 --- a/apps/octonet/ddupdate.c +++ b/apps/octonet/ddupdate.c @@ -183,7 +183,7 @@ out: int main(int argc, char **argv) { int ddbnum = 0, all = 0, i, force = 0; - char *fname; + char *fname = 0; while (1) { int option_index = 0; From ed5f89a0c4876b8ddf46c2465f7ca5db8c2ecf7a Mon Sep 17 00:00:00 2001 From: Manfred Date: Tue, 21 Jan 2020 18:36:05 +0100 Subject: [PATCH 16/55] tschecker added --- apps/tscheck.c | 109 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) create mode 100644 apps/tscheck.c diff --git a/apps/tscheck.c b/apps/tscheck.c new file mode 100644 index 0000000..56f1e3c --- /dev/null +++ b/apps/tscheck.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +char line_start[16] = ""; +char line_end[16] = "\r"; + + +uint32_t cc_errors = 0; +uint32_t packets = 0; +uint32_t payload_packets = 0; +uint32_t packet_errors = 0; + +uint8_t cc[8192] = { 0 }; + +void proc_ts(int i, uint8_t *buf) +{ + uint16_t pid=0x1fff&((buf[1]<<8)|buf[2]); + uint8_t ccin = buf[3] & 0x1F; + + if( buf[0] == 0x47 && (buf[1] & 0x80) == 0) + { + if( pid != 8191 ) + { + if( ccin != 0 ) + { + if( cc[pid] != 0 ) + { + // TODO: 1 repetition allowed + if( ((cc[pid] + 1) & 0x0F) != (ccin & 0x0F) ) + cc_errors += 1; + } + cc[pid] = ccin; + } + payload_packets += 1; + } + } + else + packet_errors += 1; + + if( (packets & 0x3FFF ) == 0) + { + printf("%s Packets: %12u non null %12u, errors: %12u, CC errors: %12u%s", line_start, packets, payload_packets, packet_errors, cc_errors, line_end); + fflush(stdout); + } + + packets += 1; +} + +#define TSBUFSIZE (100*188) + +void citest(char* n) +{ + uint8_t *buf; + uint8_t id; + int i, nts; + int len; + int ts=open(n, O_RDONLY); + buf=(uint8_t *)malloc(TSBUFSIZE); + + + while(1) { + len=read(ts, buf, TSBUFSIZE); + if (len<0) { + continue; + } + if (buf[0]!=0x47) { + read(ts, buf, 1); + continue; + } + if (len%188) { /* should not happen */ + printf("blah\n"); + continue; + } + nts=len/188; + for (i=0; i| []\n"); + exit(0); + } + if( argc > 2 ) + { + int line = atoi(argv[2]); + if( line >= 0 && line < 64 ) + { + snprintf(line_start,sizeof(line_start)-1,"\0337\033[%d;0H",line); + strncpy(line_end,"\0338",sizeof(line_end)-1); + } + } + citest(argv[1]); +} + From 03cc9ae142d55e2fb3156e4d0551b8421659e099 Mon Sep 17 00:00:00 2001 From: Manfred Date: Tue, 21 Jan 2020 19:05:56 +0100 Subject: [PATCH 17/55] tscheck don't check cc if payload bit not set --- apps/tscheck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tscheck.c b/apps/tscheck.c index 56f1e3c..8e2d936 100644 --- a/apps/tscheck.c +++ b/apps/tscheck.c @@ -37,7 +37,7 @@ void proc_ts(int i, uint8_t *buf) if( cc[pid] != 0 ) { // TODO: 1 repetition allowed - if( ((cc[pid] + 1) & 0x0F) != (ccin & 0x0F) ) + if( ( cc[pid] & 0x10 ) != 0 && (((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) ) cc_errors += 1; } cc[pid] = ccin; From 83cfff7082fcf0c954303babbed11ba33b851d2a Mon Sep 17 00:00:00 2001 From: Manfred Date: Tue, 21 Jan 2020 19:09:16 +0100 Subject: [PATCH 18/55] tscheck stupid error on previous commit --- apps/tscheck.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/tscheck.c b/apps/tscheck.c index 8e2d936..2a02648 100644 --- a/apps/tscheck.c +++ b/apps/tscheck.c @@ -37,7 +37,7 @@ void proc_ts(int i, uint8_t *buf) if( cc[pid] != 0 ) { // TODO: 1 repetition allowed - if( ( cc[pid] & 0x10 ) != 0 && (((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) ) + if( ( ccin & 0x10 ) != 0 && (((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) ) cc_errors += 1; } cc[pid] = ccin; From 5f648d7a02a74be53b35e1ce68573543362251d3 Mon Sep 17 00:00:00 2001 From: none Date: Wed, 22 Jan 2020 09:58:13 +0100 Subject: [PATCH 19/55] cleanup --- apps/flashprog.c | 4 +- apps/octonet/Makefile | 4 +- apps/octonet/ddtest.c | 10 +-- apps/octonet/ddupdate.c | 55 +++++++------ apps/octonet/flash.c | 175 +++++++++++++++++++++++----------------- apps/octonet/flash.h | 1 + 6 files changed, 143 insertions(+), 106 deletions(-) diff --git a/apps/flashprog.c b/apps/flashprog.c index 8546f9d..841b72e 100644 --- a/apps/flashprog.c +++ b/apps/flashprog.c @@ -43,7 +43,7 @@ void get_ddid(int ddb, struct ddb_id *ddbid) { if (ioctl(ddb, IOCTL_DDB_ID, ddbid)>=0) return; memset(ddbid, 0, sizeof(*ddbid)); - flashread(ddb, id, 0, 4); + flashread(ddb, linknr, id, 0, 4); printf("%02x %02x %02x %02x\n", id[0], id[1], id[2], id[3]); ddbid->subvendor=(id[0] << 8) | id[1]; @@ -158,7 +158,7 @@ int main(int argc, char **argv) #endif if (dump) { - flashdump(ddb, dump, 128); + flashdump(ddb, linknr, dump, 128); return 0; } diff --git a/apps/octonet/Makefile b/apps/octonet/Makefile index bcc10c8..0d29c03 100644 --- a/apps/octonet/Makefile +++ b/apps/octonet/Makefile @@ -6,10 +6,10 @@ install: all install -m 0755 octokey $(DESTDIR)/usr/bin install -m 0755 ddflash $(DESTDIR)/usr/bin -ddflash: ddflash.c +ddflash: ddflash.c flash.h flash.c $(CC) -o ddflash ddflash.c -ddtest: ddtest.c +ddtest: ddtest.c flash.h flash.c $(CC) -o ddtest ddtest.c octonet: octonet.c diff --git a/apps/octonet/ddtest.c b/apps/octonet/ddtest.c index ba8e9fe..58070c3 100644 --- a/apps/octonet/ddtest.c +++ b/apps/octonet/ddtest.c @@ -63,7 +63,7 @@ int ReadFlash(int ddb, int argc, char *argv[], uint32_t Flags) write(fd, Buffer, Len); close(fd); } else - Dump(Buffer,Start,Len); + dump(Buffer,Start,Len); free(Buffer); return 0; @@ -192,7 +192,7 @@ int ReadDeviceMemory(int dev,int argc, char* argv[],uint32_t Flags) struct ddb_mem mem = {.off=Start, .len=Len, .buf=Buffer }; ioctl(dev, IOCTL_DDB_READ_MEM, &mem); } - Dump(Buffer,Start,Len); + dump(Buffer,Start,Len); free(Buffer); return 0; } @@ -340,7 +340,7 @@ int flashioc(int dev,int argc, char* argv[],uint32_t Flags) } if( ReadLen > 0 ) - Dump(Buffer,0,ReadLen); + dump(Buffer,0,ReadLen); return 0; @@ -1248,7 +1248,7 @@ int lic_import(int dev, int argc, char* argv[], uint32_t Flags) return -1; } - Dump(Buffer,0,24); + dump(Buffer,0,24); Flash = FlashDetect(dev); switch(Flash) { @@ -1410,7 +1410,7 @@ int i2cread(int dev, int argc, char* argv[], uint32_t Flags) } if (!Silent) { printf("OK\n"); - Dump(&Buffer[0],0,ReadLen); + dump(&Buffer[0],0,ReadLen); } } while (Repeat); free(Buffer); diff --git a/apps/octonet/ddupdate.c b/apps/octonet/ddupdate.c index a3d4f26..bc8ca8d 100644 --- a/apps/octonet/ddupdate.c +++ b/apps/octonet/ddupdate.c @@ -100,7 +100,11 @@ static int update_flash(struct ddflash *ddf) if (!fname) fname = devid2fname(ddf->id.device, &name); 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) stat |= 1; return stat; @@ -108,12 +112,10 @@ static int update_flash(struct ddflash *ddf) return stat; } -static int ddupdate(struct ddflash *ddf) +static int update_link(struct ddflash *ddf) { int ret; - if (verbose >= 2) - printf("Detect flash type\n"); ret = flash_detect(ddf); if (ret < 0) return ret; @@ -125,7 +127,7 @@ static int ddupdate(struct ddflash *ddf) return ret; } -static int proc_card(int ddbnum, char *fname) +static int update_card(int ddbnum, char *fname) { struct ddflash ddf; char ddbname[80]; @@ -133,8 +135,6 @@ static int proc_card(int ddbnum, char *fname) int ddb, ret, link, links; sprintf(ddbname, "/dev/ddbridge/card%d", ddbnum); - if (verbose >= 2) - printf("Update card %s\n", ddbname); ddb = open(ddbname, O_RDWR); if (ddb < 0) return -3; @@ -158,19 +158,19 @@ static int proc_card(int ddbnum, char *fname) case 0x300: case 0x301: case 0x307: - links = 1; + links = 2; break; default: break; } } - //printf("%08x %08x\n", ddf.id.device, ddf.id.subdevice); if (ddf.id.device) { - ret = ddupdate(&ddf); - if (ret < 0) - break; + printf("\n\nUpdate card %s link %u:\n", ddbname, link); + ret = update_link(&ddf); + //if (ret < 0) + // break; } } @@ -179,10 +179,19 @@ out: return ret; } +usage() +{ + printf("ddupdate [OPTION]\n\n" + "-n N\n only update card N (default with N=0)\n\n" + "-a \n update all cards\n\n" + "-b file\n fpga image file override (ignored if -a is used)\n\n" + "-v \n more verbose (up to -v -v -v)\n\n" + ); +} int main(int argc, char **argv) { - int ddbnum = 0, all = 0, i, force = 0; + int ddbnum = -1, all = 0, i, force = 0; char *fname = 0; while (1) { @@ -212,12 +221,7 @@ int main(int argc, char **argv) verbose++; break; case 'h': - printf("ddupdate [OPTION]\n\n" - "-n N\n only update card N (default with N=0)\n\n" - "-a \n update all cards\n\n" - "-b file\n fpga image file override (not if -a is used)\n\n" - "-v \n more verbose (up to -v -v -v)\n\n" - ); + usage(); break; default: break; @@ -227,12 +231,17 @@ int main(int argc, char **argv) if (optind < argc) { printf("Warning: unused arguments\n"); } - + if (!all && (ddbnum < 0)) { + printf("Select card number or all cards\n\n"); + usage(); + return -1; + } + if (!all) - return proc_card(ddbnum, fname); + return update_card(ddbnum, fname); - for (i = 0; i < 20; i++) { - int ret = proc_card(i, 0); + for (i = 0; i < 100; i++) { + int ret = update_card(i, 0); if (ret == -3) /* could not open, no more cards! */ break; diff --git a/apps/octonet/flash.c b/apps/octonet/flash.c index b8f2234..54df0c3 100644 --- a/apps/octonet/flash.c +++ b/apps/octonet/flash.c @@ -134,7 +134,7 @@ static int flashdetect(int fd, uint32_t *sector_size, uint32_t *flash_size) #if 1 -int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len) +int flashread(int ddb, int link, uint8_t *buf, uint32_t addr, uint32_t len) { int ret; uint8_t cmd[4]; @@ -150,7 +150,7 @@ int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len) l = 1024; else l = len; - ret = flashio(ddb, linknr, cmd, 4, buf, l); + ret = flashio(ddb, link, cmd, 4, buf, l); if (ret < 0) return ret; addr += l; @@ -169,14 +169,14 @@ static int flashread(int ddb, uint8_t *buf, uint32_t addr, uint32_t len) } #endif -int flashdump(int ddb, uint32_t addr, uint32_t len) +int flashdump(int ddb, int link, uint32_t addr, uint32_t len) { int i, j; uint8_t buf[32]; int bl = sizeof(buf); for (j=0; j 31 && b[i] < 127) ? b[i] : '.'); - printf("|\n"); - } -} - - - - int FlashWriteAtmel(int dev,uint32_t FlashOffset, uint8_t *Buffer,int BufferSize) { int err = 0; @@ -573,7 +551,7 @@ int FlashWritePageMode(int dev, uint32_t FlashOffset, { if( (j & 0xFFFF) == 0 ) { - printf(" Programm %08x\n",FlashOffset + j); + printf(" Program %08x\n",FlashOffset + j); } Cmd[0] = 0x06; // WREN @@ -656,7 +634,7 @@ int flashwrite_pagemode(struct ddflash *ddf, int dev, uint32_t FlashOffset, break; while (1) { - cmd[0] = 0x05; // RDRS + cmd[0] = 0x05; // RDSR err = flashio(ddf->fd, ddf->link, cmd, 1, &cmd[0], 1); if (err < 0) break; @@ -687,11 +665,11 @@ int flashwrite_pagemode(struct ddflash *ddf, int dev, uint32_t FlashOffset, printf("file read error %d,%d at %u\n", rlen, errno, j); return -1; } - printf ("write %u bytes at %08x\n", len, j); + //printf ("write %u bytes at %08x\n", len, j); if ((j & 0xFFFF) == 0) - printf(" Programm %08x\n", FlashOffset + j); + printf(" Program %08x\n", FlashOffset + j); cmd[0] = 0x06; // WREN err = flashio(ddf->fd, ddf->link, cmd, 1, NULL, 0); @@ -892,51 +870,50 @@ static int flash_detect(struct ddflash *ddf) if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x41) { ddf->flash_type = SSTI_SST25VF016B; - printf("Flash: SSTI SST25VF016B 16 MBit\n"); + ddf->flash_name = "SSTI SST25VF016B 16 MBit"; ddf->sector_size = 4096; ddf->size = 0x200000; } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4A) { ddf->flash_type = SSTI_SST25VF032B; - printf("Flash: SSTI SST25VF032B 32 MBit\n"); + ddf->flash_name = "SSTI SST25VF032B 32 MBit"; ddf->sector_size = 4096; ddf->size = 0x400000; } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4B) { ddf->flash_type = SSTI_SST25VF064C; - printf("Flash: SSTI SST25VF064C 64 MBit\n"); + ddf->flash_name = "SSTI SST25VF064C 64 MBit"; ddf->sector_size = 4096; ddf->size = 0x800000; } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x15) { ddf->flash_type = SPANSION_S25FL116K; - printf("Flash: SPANSION S25FL116K 16 MBit\n"); + ddf->flash_name = "SPANSION S25FL116K 16 MBit"; ddf->sector_size = 4096; ddf->size = 0x200000; } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x16) { ddf->flash_type = SPANSION_S25FL132K; - printf("Flash: SPANSION S25FL132K 32 MBit\n"); + ddf->flash_name = "SPANSION S25FL132K 32 MBit"; ddf->sector_size = 4096; ddf->size = 0x400000; } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x17) { ddf->flash_type = SPANSION_S25FL164K; - printf("Flash: SPANSION S25FL164K 64 MBit\n"); + ddf->flash_name = "SPANSION S25FL164K 64 MBit"; ddf->sector_size = 4096; ddf->size = 0x800000; } else if (id[0] == 0x1F && id[1] == 0x28) { ddf->flash_type = ATMEL_AT45DB642D; - printf("Flash: Atmel AT45DB642D 64 MBit\n"); + ddf->flash_name = "Atmel AT45DB642D 64 MBit"; ddf->sector_size = 1024; ddf->size = 0x800000; } else if (id[0] == 0xef && id[1] == 0x40 && id[2] == 0x15) { ddf->flash_type = WINBOND_W25Q16JV; - printf("Flash: Winbond W25Q16JV 16 MBit\n"); + ddf->flash_name = "Winbond W25Q16JV 16 MBit"; ddf->sector_size = 4096; ddf->size = 0x200000; } else { - printf("Unknown Flash Flash ID = %02x %02x %02x\n", id[0], id[1], id[2]); + printf("Unknown Flash Flash ID = %02x %02x %02x !!!\n", id[0], id[1], id[2]); return -1; } if (ddf->sector_size) { ddf->buffer = malloc(ddf->sector_size); - //printf("allocated buffer %08x@%08x\n", ddf->sector_size, (uint32_t) ddf->buffer); if (!ddf->buffer) return -1; } @@ -985,82 +962,82 @@ static char *devid2fname(uint16_t devid, char **name) switch (devid) { case 0x0002: fname="DVBBridgeV1A_DVBBridgeV1A.bit"; - *name = "Octopus 35\n"; + *name = "Octopus 35"; break; case 0x0003: fname="DVBBridgeV1B_DVBBridgeV1B.fpga"; - *name = "Octopus\n"; + *name = "Octopus"; break; case 0x0005: fname="DVBBridgeV2A_DD01_0005_STD.fpga"; - *name = "Octopus Classic\n"; + *name = "Octopus Classic"; break; case 0x0006: fname="DVBBridgeV2A_DD01_0006_STD.fpga"; - *name = "CineS2 V7\n"; + *name = "CineS2 V7"; break; case 0x0007: fname="DVBBridgeV2A_DD01_0007_MXL.fpga"; - *name = "Octopus 4/8\n"; + *name = "Octopus 4/8"; break; case 0x0008: fname="DVBBridgeV2A_DD01_0008_CXD.fpga"; - *name = "Octopus 4/8\n"; + *name = "Octopus 4/8"; break; case 0x0009: fname="DVBBridgeV2A_DD01_0009_SX8.fpga"; - *name = "Octopus MAXSX8\n"; + *name = "Octopus MAXSX8"; break; case 0x000b: fname="DVBBridgeV2A_DD01_000B_SX8.fpga"; - *name = "Octopus MAXSX8 Basic\n"; + *name = "Octopus MAXSX8 Basic"; break; case 0x000a: fname="DVBBridgeV2A_DD01_000A_M4.fpga"; - *name = "Octopus MAXM4\n"; + *name = "Octopus MAXM4"; break; case 0x0011: fname="DVBBridgeV2B_DD01_0011.fpga"; - *name = "Octopus CI\n"; + *name = "Octopus CI"; break; case 0x0012: fname="DVBBridgeV2B_DD01_0012_STD.fpga"; - *name = "Octopus CI\n"; + *name = "Octopus CI"; break; case 0x0013: fname="DVBBridgeV2B_DD01_0013_PRO.fpga"; - *name = "Octopus PRO\n"; + *name = "Octopus PRO"; break; case 0x0020: fname="DVBBridgeV2C_DD01_0020.fpga"; - *name = "Octopus GT Mini\n"; + *name = "Octopus GT Mini"; break; case 0x0201: fname="DVBModulatorV1B_DVBModulatorV1B.bit"; - *name = "Modulator\n"; + *name = "Modulator"; break; case 0x0203: fname="DVBModulatorV1B_DD01_0203.fpga"; - *name = "Modulator Test\n"; + *name = "Modulator Test"; break; case 0x0210: fname="DVBModulatorV2A_DD01_0210.fpga"; - *name = "Modulator V2\n"; + *name = "Modulator V2"; break; case 0x0220: fname="SDRModulatorV1A_DD01_0220.fpga"; - *name = "SDRModulator ATV\n"; + *name = "SDRModulator ATV"; break; case 0x0221: fname="SDRModulatorV1A_DD01_0221_IQ.fpga"; - *name = "SDRModulator IQ\n"; + *name = "SDRModulator IQ"; break; case 0x0222: fname="SDRModulatorV1A_DD01_0222_DVBT.fpga"; - *name = "SDRModulator DVBT\n"; + *name = "SDRModulator DVBT"; break; default: - *name = "UNKNOWN\n"; + *name = "UNKNOWN"; break; } return fname; @@ -1085,11 +1062,11 @@ static int flashcmp(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxlen, printf("file too big\n"); return -1; } - printf("flash file len %u, compare to %08x in flash\n", len, addr); + //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) bl = len - j; - flashread(ddf->fd, buf, addr, bl); + flashread(ddf->fd, ddf->link, buf, addr, bl); rlen = read(fs, buf2, bl); if (rlen < 0 || rlen != bl) { printf("read error\n"); @@ -1098,15 +1075,60 @@ 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, 32); - dump(buf2, 32); + dump(buf, bl); + printf("\n"); + dump(buf2, bl); return addr; } } - printf("flash same as file\n"); + //printf("flash same as file\n"); return -2; } +static uint32_t crctab[] = { + 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, +}; + +static uint32_t crc32(uint8_t *buf, uint32_t len) +{ + uint32_t crc = 0xFFFFFFFF, j; + + for (j = 0; j < len; j++) + crc = ((crc << 8) ^ crctab[(crc >> 24) ^ buf[j]]); + return crc; +} + static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off) { int fd, fsize, ret = 0; @@ -1117,7 +1139,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 = 1024 * 1024; + uint32_t maxlen = 2 * 1024 * 1024, crc; fd = open(fn, O_RDONLY); if (fd < 0) { @@ -1128,10 +1150,12 @@ static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off) if (off < 0) return -1; fsize = off; +#if 0 if (fsize > maxlen) { close(fd); return -1; } +#endif lseek(fd, 0, SEEK_SET); buf = malloc(fsize); if (!buf) @@ -1177,17 +1201,20 @@ static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off) sscanf(val, "%x", &version); } else if (!strcasecmp(key, "Length")) { sscanf(val, "%u", &length); + } else if (!strcasecmp(key, "CRC")) { + sscanf(val, "%x", &crc); } } p++; *fw_off = p; - printf("devid = %04x\n", devid); - printf("version = %08x %08x\n", version, ddf->id.hw); - printf("length = %u\n", length); - printf("fsize = %u, p = %u, f-p = %u\n", fsize, p, fsize - p); + printf(" CRC = %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 (devid == ddf->id.device) { if (version <= (ddf->id.hw & 0xffffff)) { - printf("%s: older or same version\n", fn); + printf("%s is older or same version as flash\n", fn); ret = -3; /* same id but no newer version */ } } else @@ -1195,7 +1222,7 @@ static int check_fw(struct ddflash *ddf, char *fn, uint32_t *fw_off) out: free(buf); - printf("check_fw = %d\n", ret); + //printf("check_fw = %d\n", ret); return ret; } @@ -1207,7 +1234,7 @@ static int update_image(struct ddflash *ddf, char *fn, int fs, res = 0; uint32_t fw_off = 0; - printf("Check %s\n", fn); + printf("File: %s\n", fn); if (has_header) { int ck; @@ -1224,7 +1251,7 @@ static int update_image(struct ddflash *ddf, char *fn, } res = flashcmp(ddf, fs, adr, len, fw_off); if (res == -2) { - printf("%s: same as flash\n", fn); + printf("Flash already identical to %s\n", fn); } if (res < 0) goto out; diff --git a/apps/octonet/flash.h b/apps/octonet/flash.h index 60c5235..80701c8 100644 --- a/apps/octonet/flash.h +++ b/apps/octonet/flash.h @@ -82,6 +82,7 @@ struct ddflash { struct ddb_id id; uint32_t version; + char *flash_name; uint32_t flash_type; uint32_t sector_size; uint32_t size; From 938090b5e69aa8ec86f57dba7747e5b51b9f1213 Mon Sep 17 00:00:00 2001 From: none Date: Mon, 27 Jan 2020 09:41:32 +0100 Subject: [PATCH 20/55] too few arguments --- apps/octonet/ddtest.c | 20 ++++++++++---------- apps/octonet/flash.c | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/apps/octonet/ddtest.c b/apps/octonet/ddtest.c index 58070c3..5fec02d 100644 --- a/apps/octonet/ddtest.c +++ b/apps/octonet/ddtest.c @@ -53,7 +53,7 @@ int ReadFlash(int ddb, int argc, char *argv[], uint32_t Flags) } Buffer = malloc(Len); - if (flashread(ddb, Buffer, Start, Len) < 0) { + if (flashread(ddb, linknr, Buffer, Start, Len) < 0) { printf("flashread error\n"); free(Buffer); return 0; @@ -63,7 +63,7 @@ int ReadFlash(int ddb, int argc, char *argv[], uint32_t Flags) write(fd, Buffer, Len); close(fd); } else - dump(Buffer,Start,Len); + Dump(Buffer,Start,Len); free(Buffer); return 0; @@ -83,7 +83,7 @@ int ReadSave(int ddb, int argc, char *argv[], uint32_t Flags) Len = strtoul(argv[1],NULL,16); Buffer = malloc(Len); - if (flashread(ddb, Buffer, Start, Len) < 0) { + if (flashread(ddb, linknr, Buffer, Start, Len) < 0) { printf("flashread error\n"); free(Buffer); return 0; @@ -192,7 +192,7 @@ int ReadDeviceMemory(int dev,int argc, char* argv[],uint32_t Flags) struct ddb_mem mem = {.off=Start, .len=Len, .buf=Buffer }; ioctl(dev, IOCTL_DDB_READ_MEM, &mem); } - dump(Buffer,Start,Len); + Dump(Buffer,Start,Len); free(Buffer); return 0; } @@ -340,7 +340,7 @@ int flashioc(int dev,int argc, char* argv[],uint32_t Flags) } if( ReadLen > 0 ) - dump(Buffer,0,ReadLen); + Dump(Buffer,0,ReadLen); return 0; @@ -535,7 +535,7 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags) printf("out of memory\n"); return 0; } - if (flashread(dev, CmpBuffer, FlashOffset, 0x10000)<0) { + if (flashread(dev, linknr, CmpBuffer, FlashOffset, 0x10000)<0) { printf("Ioctl returns error\n"); free(Buffer); free(CmpBuffer); @@ -662,7 +662,7 @@ int FlashVerify(int dev,int argc, char* argv[],uint32_t Flags) // Place our own header } #endif - if (flashread(dev, Buffer2, FlashOffset, BufferSize)<0) { + if (flashread(dev, linknr, Buffer2, FlashOffset, BufferSize)<0) { printf("Ioctl returns error\n"); free(Buffer); free(Buffer2); @@ -1114,7 +1114,7 @@ char *GetSerNbr(int dev) int i; memset(Buffer,0,sizeof(Buffer)); - if (flashread(dev, Buffer, Start, sizeof(Buffer) - 1)) + if (flashread(dev, linknr, Buffer, Start, sizeof(Buffer) - 1)) { printf("Ioctl returns error\n"); return NULL; @@ -1248,7 +1248,7 @@ int lic_import(int dev, int argc, char* argv[], uint32_t Flags) return -1; } - dump(Buffer,0,24); + Dump(Buffer,0,24); Flash = FlashDetect(dev); switch(Flash) { @@ -1410,7 +1410,7 @@ int i2cread(int dev, int argc, char* argv[], uint32_t Flags) } if (!Silent) { printf("OK\n"); - dump(&Buffer[0],0,ReadLen); + Dump(&Buffer[0],0,ReadLen); } } while (Repeat); free(Buffer); diff --git a/apps/octonet/flash.c b/apps/octonet/flash.c index 54df0c3..6aeab05 100644 --- a/apps/octonet/flash.c +++ b/apps/octonet/flash.c @@ -206,6 +206,26 @@ int writereg(int dev, uint32_t RegAddress, uint32_t RegValue) } +void Dump(const uint8_t *b, uint32_t start, int l) +{ + int i, j; + + for (j = 0; j < l; j += 16, b += 16) { + printf("%08x: ", start + j); + 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"); + } +} + + void dump(const uint8_t *b, int l) { From b43160a03ac4bce3dcbc95fe803d841b1ded2b83 Mon Sep 17 00:00:00 2001 From: drmocm Date: Wed, 5 Feb 2020 19:00:51 +0100 Subject: [PATCH 21/55] added continuity check option with (-a l) and without (t) display line fixed some warnings --- lib/ddzap.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 111 insertions(+), 8 deletions(-) diff --git a/lib/ddzap.c b/lib/ddzap.c index f3079e8..d375854 100644 --- a/lib/ddzap.c +++ b/lib/ddzap.c @@ -11,6 +11,81 @@ #include #include +char line_start[16] = ""; +char line_end[16] = "\r"; + + +uint32_t cc_errors = 0; +uint32_t packets = 0; +uint32_t payload_packets = 0; +uint32_t packet_errors = 0; + +uint8_t cc[8192] = { 0 }; + +void proc_ts(int i, uint8_t *buf) +{ + uint16_t pid=0x1fff&((buf[1]<<8)|buf[2]); + uint8_t ccin = buf[3] & 0x1F; + + if( buf[0] == 0x47 && (buf[1] & 0x80) == 0) + { + if( pid != 8191 ) + { + if( ccin != 0 ) + { + if( cc[pid] != 0 ) + { + // TODO: 1 repetition allowed + if( ( ccin & 0x10 ) != 0 && (((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) ) + cc_errors += 1; + } + cc[pid] = ccin; + } + payload_packets += 1; + } + } + else + packet_errors += 1; + + if( (packets & 0x3FFF ) == 0) + { + printf("%s Packets: %12u non null %12u, errors: %12u, CC errors: %12u%s", line_start, packets, payload_packets, packet_errors, cc_errors, line_end); + fflush(stdout); + } + + packets += 1; +} + +#define TSBUFSIZE (100*188) + +void tscheck(int ts) +{ + uint8_t *buf; + uint8_t id; + int i, nts; + int len; + + buf=(uint8_t *)malloc(TSBUFSIZE); + + + while(1) { + len=read(ts, buf, TSBUFSIZE); + if (len<0) { + continue; + } + if (buf[0]!=0x47) { + read(ts, buf, 1); + continue; + } + if (len%188) { /* should not happen */ + printf("blah\n"); + continue; + } + nts=len/188; + for (i=0; iname); @@ -253,11 +348,19 @@ int main(int argc, char **argv) "/dev/dvb/adapter%d/dvr%d",fe->anum, fe->fnum); fprintf(stderr,"opening %s\n", filename); if ((fd = open(filename ,O_RDONLY)) < 0){ - fprintf(stderr,"Error opening input file:%s\n",filename); + fprintf(stderr,"Error opening input file:%s\n",filename); } - while(1){ - read(fd,buf,BUFFSIZE); - write(fileno(stdout),buf,BUFFSIZE); + if (odvr == 1){ + while(1){ + read(fd,buf,BUFFSIZE); + write(fileno(stdout),buf,BUFFSIZE); + } + } else { + if( line >= 0 && line < 64 ){ + snprintf(line_start,sizeof(line_start)-1,"\0337\033[%d;0H",line); + strncpy(line_end,"\0338",sizeof(line_end)-1); + } + tscheck(fd); } } } From 5abf74a952081926664c9d9c25dfe38a01d230bd Mon Sep 17 00:00:00 2001 From: none Date: Tue, 31 Mar 2020 16:37:31 +0200 Subject: [PATCH 22/55] add yesno --- apps/octonet/ddupdate.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/apps/octonet/ddupdate.c b/apps/octonet/ddupdate.c index bc8ca8d..3faeeda 100644 --- a/apps/octonet/ddupdate.c +++ b/apps/octonet/ddupdate.c @@ -17,6 +17,20 @@ static int verbose = 0; +static int yesno() +{ + char c; + + printf("\n\nNew firmware available\nReally flash now? y/n\n"); + fflush(0); + c = getchar(); + if (c!='y') { + printf("\nFlashing aborted.\n\n"); + return 0; + } + printf("\nStarting to flash\n\n"); + return 1; +} static int update_flash(struct ddflash *ddf) { @@ -179,7 +193,7 @@ out: return ret; } -usage() +static int usage() { printf("ddupdate [OPTION]\n\n" "-n N\n only update card N (default with N=0)\n\n" From 8c950053a79a8544137f1100e3fa4846a17ba3d8 Mon Sep 17 00:00:00 2001 From: none Date: Tue, 31 Mar 2020 16:37:59 +0200 Subject: [PATCH 23/55] cleanup --- apps/octonet/flash.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/octonet/flash.c b/apps/octonet/flash.c index 6aeab05..6a91d1f 100644 --- a/apps/octonet/flash.c +++ b/apps/octonet/flash.c @@ -1140,9 +1140,10 @@ static uint32_t crctab[] = { 0xafb010b1,0xab710d06,0xa6322bdf,0xa2f33668,0xbcb4666d,0xb8757bda,0xb5365d03,0xb1f740b4, }; -static uint32_t crc32(uint8_t *buf, uint32_t len) +static uint32_t crc32(uint8_t *buf, uint32_t len, uint32_t crc) { - uint32_t crc = 0xFFFFFFFF, j; + //uint32_t crc = 0xFFFFFFFF; + uint32_t j; for (j = 0; j < len; j++) crc = ((crc << 8) ^ crctab[(crc >> 24) ^ buf[j]]); @@ -1257,7 +1258,6 @@ static int update_image(struct ddflash *ddf, char *fn, printf("File: %s\n", fn); if (has_header) { int ck; - ck = check_fw(ddf, fn, &fw_off); if (ck < 0) return ck; From 02329a7d552bb916750d4527d87a42a53c89f8bd Mon Sep 17 00:00:00 2001 From: none Date: Tue, 31 Mar 2020 16:38:49 +0200 Subject: [PATCH 24/55] check if link exists --- ddbridge/ddbridge-io.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ddbridge/ddbridge-io.c b/ddbridge/ddbridge-io.c index 6792180..4c696f3 100644 --- a/ddbridge/ddbridge-io.c +++ b/ddbridge/ddbridge-io.c @@ -65,6 +65,8 @@ u32 ddbreadl(struct ddb *dev, u32 adr) u32 val, l = (adr >> DDB_LINK_SHIFT) & 3; struct ddb_link *link = &dev->link[l]; + if (!link->regs) + return 0; spin_lock_irqsave(&link->lock, flags); gtlw(link); ddblwritel0(link, adr & 0xfffc, link->regs + 0x14); @@ -84,6 +86,8 @@ void ddbwritel(struct ddb *dev, u32 val, u32 adr) u32 l = (adr >> DDB_LINK_SHIFT); struct ddb_link *link = &dev->link[l]; + if (!link->regs) + return; spin_lock_irqsave(&link->lock, flags); gtlw(link); ddblwritel0(link, 0xf0000 | (adr & 0xfffc), link->regs + 0x14); From 5138ba3f918f2edfd60a24068e9bb8ed6103e4e2 Mon Sep 17 00:00:00 2001 From: none Date: Tue, 31 Mar 2020 16:39:32 +0200 Subject: [PATCH 25/55] support high voltage setting on MAX cards --- ddbridge/ddbridge-max.c | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/ddbridge/ddbridge-max.c b/ddbridge/ddbridge-max.c index 6ed59bd..9a58602 100644 --- a/ddbridge/ddbridge-max.c +++ b/ddbridge/ddbridge-max.c @@ -357,6 +357,29 @@ static int max_set_voltage(struct dvb_frontend *fe, enum fe_sec_voltage voltage) static int max_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg) { + struct ddb_input *input = fe->sec_priv; + struct ddb_port *port = input->port; + struct ddb *dev = port->dev; + u32 tag = DDB_LINK_TAG(port->lnr); + struct ddb_dvb *dvb = &port->dvb[input->nr & 1]; + u32 fmode = dev->link[port->lnr].lnb.fmode; + + mutex_lock(&dev->link[port->lnr].lnb.lock); + switch (fmode) { + default: + case 0: + case 3: + ddbwritel(dev, arg ? 0x34 : 0x01, tag | LNB_CONTROL(dvb->input)); + break; + case 1: + case 2: + ddbwritel(dev, arg ? 0x34 : 0x01, tag | LNB_CONTROL(0)); + ddbwritel(dev, arg ? 0x34 : 0x01, tag | LNB_CONTROL(1)); + ddbwritel(dev, arg ? 0x34 : 0x01, tag | LNB_CONTROL(2)); + ddbwritel(dev, arg ? 0x34 : 0x01, tag | LNB_CONTROL(3)); + break; + } + mutex_unlock(&dev->link[port->lnr].lnb.lock); return 0; } From 93335e856eca7c2f516299abb13afee70c878581 Mon Sep 17 00:00:00 2001 From: none Date: Tue, 31 Mar 2020 16:40:21 +0200 Subject: [PATCH 26/55] add TS_STAT --- ddbridge/ddbridge-regs.h | 1 + 1 file changed, 1 insertion(+) diff --git a/ddbridge/ddbridge-regs.h b/ddbridge/ddbridge-regs.h index afe6746..61216a8 100644 --- a/ddbridge/ddbridge-regs.h +++ b/ddbridge/ddbridge-regs.h @@ -232,6 +232,7 @@ #define TS_CONTROL(_io) ((_io)->regs + 0x00) #define TS_CONTROL2(_io) ((_io)->regs + 0x04) +#define TS_STAT(_io) ((_io)->regs + 0x08) #define TS_INPUT_CONTROL_ENABLE (0x00000001) #define TS_INPUT_CONTROL_RESET (0x00000002) From ee6eab9eadc704123c00fb8a253c164ce663f949 Mon Sep 17 00:00:00 2001 From: none Date: Tue, 31 Mar 2020 16:42:25 +0200 Subject: [PATCH 27/55] change IQ mode setting --- ddbridge/ddbridge-sx8.c | 79 +++++++++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 26 deletions(-) diff --git a/ddbridge/ddbridge-sx8.c b/ddbridge/ddbridge-sx8.c index e0ee5bf..ab07ecd 100644 --- a/ddbridge/ddbridge-sx8.c +++ b/ddbridge/ddbridge-sx8.c @@ -138,7 +138,6 @@ static int read_status(struct dvb_frontend *fe, enum fe_status *status) dvbs2_bits_per_symbol[ state->mci.signal_info. dvbs2_signal_info.pls_code]; - //printk("PLS %02x\n", state->mci.signal_info.dvbs2_signal_info.pls_code); } else sx8_base->used_ldpc_bitrate[state->mci.nr] = 0; } @@ -165,6 +164,7 @@ static int stop_iq(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; if (!state->iq_started) return -1; @@ -173,8 +173,19 @@ static int stop_iq(struct dvb_frontend *fe) cmd.demod = state->mci.demod; ddb_mci_cmd(&state->mci, &cmd, NULL); ddb_mci_config(&state->mci, SX8_TSCONFIG_MODE_NORMAL); - state->iq_started = 0; + + mutex_lock(&mci_base->tuner_lock); + sx8_base->tuner_use_count[input]--; + if (!sx8_base->tuner_use_count[input]) + mci_set_tuner(fe, input, 0); + if (state->mci.demod != SX8_DEMOD_NONE) { + sx8_base->demod_in_use[state->mci.demod] = 0; + state->mci.demod = SX8_DEMOD_NONE; + } + sx8_base->used_ldpc_bitrate[state->mci.nr] = 0; sx8_base->iq_mode = 0; + state->iq_started = 0; + mutex_unlock(&mci_base->tuner_lock); return 0; } @@ -229,7 +240,14 @@ static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config) u32 input = state->mci.tuner; u32 bits_per_symbol = 0; int i = -1, stat = 0; + struct ddb_link *link = state->mci.base->link; + if (link->ids.device == 0x000b) { + /* Mask out higher modulations and MIS for Basic + or search command will fail */ + modmask &= 3; + p->stream_id = NO_STREAM_ID_FILTER; + } if (p->symbol_rate >= MCLK / 2) flags &= ~1; if ((flags & 3) == 0) @@ -244,7 +262,6 @@ static int start(struct dvb_frontend *fe, u32 flags, u32 modmask, u32 ts_config) bits_per_symbol++; } } - mutex_lock(&mci_base->tuner_lock); if (sx8_base->iq_mode) { stat = -EBUSY; @@ -358,34 +375,36 @@ 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 (sx8_base->iq_mode) { - stat = -EBUSY; - goto unlock; + if (!state->iq_started) { + mutex_lock(&mci_base->tuner_lock); + if (sx8_base->iq_mode) { + stat = -EBUSY; + goto unlock; + } + for (i = 0; i < SX8_DEMOD_NUM; i++) + if (sx8_base->demod_in_use[i]) + used_demods++; + if (used_demods > 0) { + stat = -EBUSY; + goto unlock; + } + state->mci.demod = 0; + if (!sx8_base->tuner_use_count[input]) + mci_set_tuner(fe, input, 1); + sx8_base->tuner_use_count[input]++; + sx8_base->iq_mode = (ts_config > 1); + unlock: + mutex_unlock(&mci_base->tuner_lock); + if (stat) + return stat; } - for (i = 0; i < SX8_DEMOD_NUM; i++) - if (sx8_base->demod_in_use[i]) - used_demods++; - if (used_demods > 0) { - stat = -EBUSY; - goto unlock; - } - state->mci.demod = 0; - if (!sx8_base->tuner_use_count[input]) - mci_set_tuner(fe, input, 1); - sx8_base->tuner_use_count[input]++; - sx8_base->iq_mode = (ts_config > 1); -unlock: - mutex_unlock(&mci_base->tuner_lock); - if (stat) - return stat; - memset(&cmd, 0, sizeof(cmd)); cmd.command = SX8_CMD_START_IQ; - cmd.sx8_start_iq.flags = flags; + cmd.sx8_start_iq.flags = flags >> 8; cmd.sx8_start_iq.roll_off = roll_off; cmd.sx8_start_iq.frequency = p->frequency * 1000; cmd.sx8_start_iq.symbol_rate = p->symbol_rate; + cmd.sx8_start_iq.gain = flags & 0xff; cmd.tuner = state->mci.tuner; cmd.demod = state->mci.demod; stat = ddb_mci_cmd(&state->mci, &cmd, NULL); @@ -395,6 +414,13 @@ unlock: return stat; } +static int set_lna(struct dvb_frontend *fe) +{ + printk("set_lna\n"); + return 0; +} + + static int set_parameters(struct dvb_frontend *fe) { int stat = 0; @@ -441,7 +467,7 @@ static int set_parameters(struct dvb_frontend *fe) state->mci.signal_info.status = MCI_DEMOD_WAIT_SIGNAL; } } else { - stat = start_iq(fe, iq_mode & 1, 4, ts_config); + stat = start_iq(fe, (isi >> 8) & 0xffff, 4, ts_config); if (!stat) { state->iq_started = 1; state->first_time_lock = 1; @@ -530,6 +556,7 @@ static struct dvb_frontend_ops sx8_ops = { .release = release, .read_status = read_status, .set_input = set_input, + .set_lna = set_lna, .sleep = sleep, }; From 54e8bb1575ab4f5c23199e11354c307655c1aa08 Mon Sep 17 00:00:00 2001 From: none Date: Tue, 31 Mar 2020 16:43:18 +0200 Subject: [PATCH 28/55] add packet loss and stall counter --- ddbridge/ddbridge-core.c | 28 ++++++++++++++++++++++------ ddbridge/ddbridge.h | 3 +++ 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/ddbridge/ddbridge-core.c b/ddbridge/ddbridge-core.c index 64150d2..829e604 100644 --- a/ddbridge/ddbridge-core.c +++ b/ddbridge/ddbridge-core.c @@ -532,6 +532,14 @@ static void ddb_input_stop_unlocked(struct ddb_input *input) if (input->dma) { ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); input->dma->running = 0; + if (input->dma->stall_count) + dev_warn(input->port->dev->dev, + "DMA stalled %u times!\n", + input->dma->stall_count); + if (input->dma->packet_loss) + dev_warn(input->port->dev->dev, + "%u packets lost due to low DMA performance!\n", + input->dma->packet_loss); } } @@ -554,6 +562,8 @@ static void ddb_input_start_unlocked(struct ddb_input *input) input->dma->cbuf = 0; input->dma->coff = 0; input->dma->stat = 0; + input->dma->stall_count = 0; + input->dma->packet_loss = 0; ddbwritel(dev, 0, DMA_BUFFER_CONTROL(input->dma)); } ddbwritel(dev, 0, TS_CONTROL(input)); @@ -2424,10 +2434,19 @@ static void input_tasklet(unsigned long data) dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); -#if 0 - if (4 & dma->ctrl) - dev_err(dev->dev, "Overflow dma %d\n", dma->nr); +#if 1 + { + u32 packet_loss = dma->packet_loss; + u32 cur_counter = 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; + } #endif + if (4 & dma->ctrl) + dma->stall_count++; if (input->redi) input_write_dvb(input, input->redi); if (input->redo) @@ -4175,9 +4194,6 @@ static struct device_attribute ddb_attrs_fanspeed[] = { static struct class ddb_class = { .name = "ddbridge", .owner = THIS_MODULE, -#if 0 - .dev_attrs = ddb_attrs, -#endif .devnode = ddb_devnode, }; diff --git a/ddbridge/ddbridge.h b/ddbridge/ddbridge.h index 7fd0823..ff35992 100644 --- a/ddbridge/ddbridge.h +++ b/ddbridge/ddbridge.h @@ -214,6 +214,9 @@ struct ddb_dma { u32 ctrl; u32 cbuf; u32 coff; + + u32 stall_count; + u32 packet_loss; }; struct ddb_dvb { From c1100645be1c9bab3c9bb839e6c30f2b4c8ea3b3 Mon Sep 17 00:00:00 2001 From: none Date: Mon, 3 Aug 2020 17:47:19 +0200 Subject: [PATCH 29/55] typo --- lib/src/config.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/config.c b/lib/src/config.c index 0b67a99..53e9943 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 fiile %s not found\n", fname); + printf("config file %s not found\n", fname); return -1; } From cbf73572b7af136168533d3bbb68360004d00a53 Mon Sep 17 00:00:00 2001 From: none Date: Wed, 26 Aug 2020 10:30:22 +0200 Subject: [PATCH 30/55] allow input selection in normal LNB mode --- lib/src/dvb.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/src/dvb.c b/lib/src/dvb.c index 3245c8e..618eb03 100644 --- a/lib/src/dvb.c +++ b/lib/src/dvb.c @@ -231,6 +231,7 @@ static int set_en50607(struct dddvb_fe *fe, uint32_t freq, uint32_t sr, uint32_t input = 3 & (sat >> 6); int fd = fe->fd; + //printf("input = %u, sat = %u\n", input, sat&0x3f); hor &= 1; cmd.msg[1] = slot << 3; cmd.msg[1] |= ((t >> 8) & 0x07); @@ -317,9 +318,13 @@ static int tune_sat(struct dddvb_fe *fe) fe->scif_slot, fe->scif_freq, ds); pthread_mutex_unlock(&fe->dd->uni_lock); } else { + uint32_t input = lnb; + + 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); - set_fe_input(fe, freq, fe->param.param[PARAM_SR], ds, ~(0U)); + set_fe_input(fe, freq, fe->param.param[PARAM_SR], ds, input); } } From 67a13e4f3476bf20ec8988419cbed05dbf375d2c Mon Sep 17 00:00:00 2001 From: none Date: Sat, 29 Aug 2020 14:32:18 +0200 Subject: [PATCH 31/55] use uint32_t for sizes --- apps/octonet/ddtest.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/octonet/ddtest.c b/apps/octonet/ddtest.c index 5fec02d..79d0d1f 100644 --- a/apps/octonet/ddtest.c +++ b/apps/octonet/ddtest.c @@ -386,8 +386,8 @@ int FlashProg(int dev,int argc, char* argv[],uint32_t Flags) int BufferSize = 0; int BlockErase = 0; uint32_t FlashOffset = 0x10000; - int SectorSize = 0; - int FlashSize = 0; + uint32_t SectorSize = 0; + uint32_t FlashSize = 0; int ValidateFPGAType = 1; int Flash; uint32_t Id1, Id2; From ed8bb5af82d62bcd7842e1df89e23344fc445211 Mon Sep 17 00:00:00 2001 From: none Date: Sat, 29 Aug 2020 14:33:15 +0200 Subject: [PATCH 32/55] add new flash types and consolidate old duplicate functions --- apps/octonet/flash.c | 246 +++++++++++++++---------------------------- apps/octonet/flash.h | 11 ++ 2 files changed, 93 insertions(+), 164 deletions(-) diff --git a/apps/octonet/flash.c b/apps/octonet/flash.c index 6a91d1f..a71886f 100644 --- a/apps/octonet/flash.c +++ b/apps/octonet/flash.c @@ -14,124 +14,101 @@ int flashio(int ddb, int link, return ioctl(ddb, IOCTL_DDB_FLASHIO, &fio); } -int FlashDetect(int dev) +static int flash_id(int fd, int link, uint8_t *id) { - uint8_t Cmd = 0x9F; - uint8_t Id[3]; + uint8_t cmd = 0x9F; - int r = flashio(dev, linknr, &Cmd, 1, Id, 3); - if (r < 0) - return r; - - if (Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x41) - r = SSTI_SST25VF016B; - else if (Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x4A) - r = SSTI_SST25VF032B; - else if ( Id[0] == 0xBF && Id[1] == 0x25 && Id[2] == 0x4B ) - r = SSTI_SST25VF064C; - else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x15 ) - r = SPANSION_S25FL116K; - else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x16 ) - r = SPANSION_S25FL132K; - else if ( Id[0] == 0x01 && Id[1] == 0x40 && Id[2] == 0x17 ) - r = SPANSION_S25FL164K; - else if ( Id[0] == 0x1F && Id[1] == 0x28) - r = ATMEL_AT45DB642D; - else if ( Id[0] == 0xef && Id[1] == 0x40 && Id[2] == 0x15 ) - r = WINBOND_W25Q16JV; - else - r = UNKNOWN_FLASH; - - switch(r) { - case UNKNOWN_FLASH : - printf("Unknown Flash Flash ID = %02x %02x %02x\n",Id[0],Id[1],Id[2]); - break; - case ATMEL_AT45DB642D : - printf("Flash: Atmel AT45DB642D 64 MBit\n"); - break; - case SSTI_SST25VF016B : - printf("Flash: SSTI SST25VF016B 16 MBit\n"); - break; - case SSTI_SST25VF032B : - printf("Flash: SSTI SST25VF032B 32 MBit\n"); - break; - case SSTI_SST25VF064C : - printf("Flash: SSTI SST25VF064C 64 MBit\n"); - break; - case SPANSION_S25FL116K : - printf("Flash: SPANSION S25FL116K 16 MBit\n"); - break; - case SPANSION_S25FL132K : - printf("Flash: SPANSION S25FL132K 32 MBit\n"); - break; - case SPANSION_S25FL164K : - printf("Flash: SPANSION S25FL164K 64 MBit\n"); - break; - case WINBOND_W25Q16JV : - printf("Flash: Winbond W25Q16JV 16 MBit\n"); - break; - } - return r; + return flashio(fd, link, &cmd, 1, id, 3); } -static int flashdetect(int fd, uint32_t *sector_size, uint32_t *flash_size) +struct flash_info flashs[] = { + { { 0xbf, 0x25, 0x41 }, SSTI_SST25VF016B, 4096, 0x200000, "SSTI SST25VF016B 16 MBit" }, + { { 0xbf, 0x25, 0x4a }, SSTI_SST25VF032B, 4096, 0x400000, "SSTI SST25VF032B 32 MBit" }, + { { 0xbf, 0x25, 0x4b }, SSTI_SST25VF064C, 4096, 0x400000, "SSTI SST25VF064C 64 MBit" }, + { { 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" }, + { { 0x00, 0x00, 0x00 }, UNKNOWN_FLASH, 0, 0, "Unknown" }, +}; + +static struct flash_info *flash_getinfo(uint8_t *id) +{ + struct flash_info *f= flashs; + + while (f->id[0]) { + if ((f->id[0] == id[0]) && (f->id[1] == id[1]) && + ((id[0] == 0xff) || (f->id[0] == id[0]))) + break; + f++; + } + return f; +} + +static int flashdetect(int fd, uint32_t *sector_size, uint32_t *flash_size, char **name) +{ + uint8_t id[3]; + int flash_type, r; + struct flash_info *f; + + r = flash_id(fd, linknr, id); + if (r < 0) + return r; + f = flash_getinfo(id); + printf("Flash: %s\n", f->name); + *sector_size = f->ssize; + *flash_size = f->fsize; + + if (!f->id[0]) + printf("Unknown Flash Flash ID = %02x %02x %02x\n", id[0], id[1], id[2]); + return f->type; +} + +static int flash_detect(struct ddflash *ddf) { uint8_t cmd = 0x9F; uint8_t id[3]; - int flash_type; + int r; + struct flash_info *f; - int r = flashio(fd, linknr, &cmd, 1, id, 3); + r = flash_id(ddf->fd, ddf->link, id); if (r < 0) return r; + f = flash_getinfo(id); + ddf->flash_type = f->type; + ddf->flash_name = f->name; + ddf->sector_size = f->ssize; + ddf->size = f->fsize; - if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x41) { - flash_type = SSTI_SST25VF016B; - printf("Flash: SSTI SST25VF016B 16 MBit\n"); - *sector_size = 4096; - *flash_size = 0x200000; - } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4A) { - flash_type = SSTI_SST25VF032B; - printf("Flash: SSTI SST25VF032B 32 MBit\n"); - *sector_size = 4096; - *flash_size = 0x400000; - } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4B) { - flash_type = SSTI_SST25VF064C; - printf("Flash: SSTI SST25VF064C 64 MBit\n"); - *sector_size = 4096; - *flash_size = 0x800000; - } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x15) { - flash_type = SPANSION_S25FL116K; - printf("Flash: SPANSION S25FL116K 16 MBit\n"); - *sector_size = 4096; - *flash_size = 0x200000; - } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x16) { - flash_type = SPANSION_S25FL132K; - printf("Flash: SPANSION S25FL132K 32 MBit\n"); - *sector_size = 4096; - *flash_size = 0x400000; - } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x17) { - flash_type = SPANSION_S25FL164K; - printf("Flash: SPANSION S25FL164K 64 MBit\n"); - *sector_size = 4096; - *flash_size = 0x800000; - } else if (id[0] == 0xef && id[1] == 0x40 && id[2] == 0x15) { - flash_type = WINBOND_W25Q16JV; - printf("Flash: Winbond 16 MBit\n"); - *sector_size = 4096; - *flash_size = 0x200000; - } else if (id[0] == 0x1F && id[1] == 0x28) { - flash_type = ATMEL_AT45DB642D; - printf("Flash: Atmel AT45DB642D 64 MBit\n"); - *sector_size = 1024; - *flash_size = 0x800000; - } else { - printf("Unknown Flash Flash ID = %02x %02x %02x\n", id[0], id[1], id[2]); + if (!f->id[0]) { + printf("Unknown Flash Flash ID = %02x %02x %02x !!!\n", id[0], id[1], id[2]); return -1; } - return flash_type; + if (ddf->sector_size) { + ddf->buffer = malloc(ddf->sector_size); + if (!ddf->buffer) + return -1; + } + return 0; } +int FlashDetect(int dev) +{ + uint32_t sector_size; + uint32_t flash_size; + char *name; + + return flashdetect(dev, §or_size, &flash_size, &name); +} #if 1 int flashread(int ddb, int link, uint8_t *buf, uint32_t addr, uint32_t len) @@ -873,73 +850,14 @@ static int flashwrite(struct ddflash *ddf, int fs, uint32_t addr, uint32_t maxle case SPANSION_S25FL132K: case SPANSION_S25FL164K: case WINBOND_W25Q16JV: + case WINBOND_W25Q32JV: + case WINBOND_W25Q64JV: + case WINBOND_W25Q128JV: return flashwrite_pagemode(ddf, fs, addr, 0x1c, fw_off); } return -1; } - -static int flash_detect(struct ddflash *ddf) -{ - uint8_t cmd = 0x9F; - uint8_t id[3]; - - int r = flashio(ddf->fd, ddf->link, &cmd, 1, id, 3); - if (r < 0) - return r; - - if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x41) { - ddf->flash_type = SSTI_SST25VF016B; - ddf->flash_name = "SSTI SST25VF016B 16 MBit"; - ddf->sector_size = 4096; - ddf->size = 0x200000; - } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4A) { - ddf->flash_type = SSTI_SST25VF032B; - ddf->flash_name = "SSTI SST25VF032B 32 MBit"; - ddf->sector_size = 4096; - ddf->size = 0x400000; - } else if (id[0] == 0xBF && id[1] == 0x25 && id[2] == 0x4B) { - ddf->flash_type = SSTI_SST25VF064C; - ddf->flash_name = "SSTI SST25VF064C 64 MBit"; - ddf->sector_size = 4096; - ddf->size = 0x800000; - } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x15) { - ddf->flash_type = SPANSION_S25FL116K; - ddf->flash_name = "SPANSION S25FL116K 16 MBit"; - ddf->sector_size = 4096; - ddf->size = 0x200000; - } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x16) { - ddf->flash_type = SPANSION_S25FL132K; - ddf->flash_name = "SPANSION S25FL132K 32 MBit"; - ddf->sector_size = 4096; - ddf->size = 0x400000; - } else if (id[0] == 0x01 && id[1] == 0x40 && id[2] == 0x17) { - ddf->flash_type = SPANSION_S25FL164K; - ddf->flash_name = "SPANSION S25FL164K 64 MBit"; - ddf->sector_size = 4096; - ddf->size = 0x800000; - } else if (id[0] == 0x1F && id[1] == 0x28) { - ddf->flash_type = ATMEL_AT45DB642D; - ddf->flash_name = "Atmel AT45DB642D 64 MBit"; - ddf->sector_size = 1024; - ddf->size = 0x800000; - } else if (id[0] == 0xef && id[1] == 0x40 && id[2] == 0x15) { - ddf->flash_type = WINBOND_W25Q16JV; - ddf->flash_name = "Winbond W25Q16JV 16 MBit"; - ddf->sector_size = 4096; - ddf->size = 0x200000; - } else { - printf("Unknown Flash Flash ID = %02x %02x %02x !!!\n", id[0], id[1], id[2]); - return -1; - } - if (ddf->sector_size) { - ddf->buffer = malloc(ddf->sector_size); - if (!ddf->buffer) - return -1; - } - return 0; -} - static int get_id(struct ddflash *ddf) { uint8_t id[4]; diff --git a/apps/octonet/flash.h b/apps/octonet/flash.h index 80701c8..350fabe 100644 --- a/apps/octonet/flash.h +++ b/apps/octonet/flash.h @@ -72,6 +72,17 @@ enum { SPANSION_S25FL132K = 6, SPANSION_S25FL164K = 7, WINBOND_W25Q16JV = 8, + WINBOND_W25Q32JV = 9, + WINBOND_W25Q64JV = 10, + WINBOND_W25Q128JV = 11, +}; + +struct flash_info { + uint8_t id[3]; + uint32_t type; + uint32_t ssize; + uint32_t fsize; + char *name; }; struct ddflash { From bb5e9e7f39145f0dd10831c82a08705dce053aea Mon Sep 17 00:00:00 2001 From: none Date: Sat, 29 Aug 2020 14:34:53 +0200 Subject: [PATCH 33/55] - correct style - bug in header check --- apps/tscheck.c | 86 +++++++++++++++++++++++--------------------------- 1 file changed, 40 insertions(+), 46 deletions(-) diff --git a/apps/tscheck.c b/apps/tscheck.c index 2a02648..ea132c8 100644 --- a/apps/tscheck.c +++ b/apps/tscheck.c @@ -25,49 +25,43 @@ uint8_t cc[8192] = { 0 }; void proc_ts(int i, uint8_t *buf) { - uint16_t pid=0x1fff&((buf[1]<<8)|buf[2]); - uint8_t ccin = buf[3] & 0x1F; - - if( buf[0] == 0x47 && (buf[1] & 0x80) == 0) - { - if( pid != 8191 ) - { - if( ccin != 0 ) - { - if( cc[pid] != 0 ) - { - // TODO: 1 repetition allowed - if( ( ccin & 0x10 ) != 0 && (((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) ) - cc_errors += 1; - } - cc[pid] = ccin; - } - payload_packets += 1; - } - } - else - packet_errors += 1; - - if( (packets & 0x3FFF ) == 0) - { - printf("%s Packets: %12u non null %12u, errors: %12u, CC errors: %12u%s", line_start, packets, payload_packets, packet_errors, cc_errors, line_end); - fflush(stdout); - } - - packets += 1; + uint16_t pid= 0x1fff& ((buf[1] << 8) | buf[2]); + uint8_t ccin = buf[3] & 0x1f; + + if( buf[0] == 0x47 && (buf[1] & 0x80) == 0) { + if( pid != 8191 ) { + if (ccin & 0x10) { + if( cc[pid] != 0 ) { + // TODO: 1 repetition allowed + if ((((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) ) + cc_errors += 1; + } + cc[pid] = ccin; + } + payload_packets += 1; + } + } else + packet_errors += 1; + + if( (packets & 0x3FFF ) == 0) { + printf("%s Packets: %12u non null %12u, errors: %12u, CC errors: %12u%s", + line_start, packets, payload_packets, packet_errors, cc_errors, line_end); + fflush(stdout); + } + packets += 1; } #define TSBUFSIZE (100*188) void citest(char* n) { - uint8_t *buf; + uint8_t *buf; uint8_t id; int i, nts; int len; int ts=open(n, O_RDONLY); buf=(uint8_t *)malloc(TSBUFSIZE); - + while(1) { len=read(ts, buf, TSBUFSIZE); @@ -90,20 +84,20 @@ void citest(char* n) int main(int argc, char* argv[]) { - if( argc < 2 ) - { - printf("tscheck | []\n"); - exit(0); - } - if( argc > 2 ) - { - int line = atoi(argv[2]); - if( line >= 0 && line < 64 ) - { - snprintf(line_start,sizeof(line_start)-1,"\0337\033[%d;0H",line); - strncpy(line_end,"\0338",sizeof(line_end)-1); - } - } + if( argc < 2 ) + { + printf("tscheck | []\n"); + exit(0); + } + if( argc > 2 ) + { + int line = atoi(argv[2]); + if( line >= 0 && line < 64 ) + { + snprintf(line_start,sizeof(line_start)-1,"\0337\033[%d;0H",line); + strncpy(line_end,"\0338",sizeof(line_end)-1); + } + } citest(argv[1]); } From 982dc4d3667add9a047a65b422270cca2edb8cc6 Mon Sep 17 00:00:00 2001 From: none Date: Sat, 29 Aug 2020 14:38:09 +0200 Subject: [PATCH 34/55] fix tscheck and add option to not open dvr demux --- lib/ddzap.c | 58 ++++++++++++++++++++++++---------------------- lib/src/dddvb.c | 1 + lib/src/dddvb.h | 3 +++ lib/src/dvb.c | 7 +++--- lib/src/libdddvb.h | 3 +++ 5 files changed, 40 insertions(+), 32 deletions(-) diff --git a/lib/ddzap.c b/lib/ddzap.c index d375854..519e8b8 100644 --- a/lib/ddzap.c +++ b/lib/ddzap.c @@ -27,33 +27,28 @@ 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 != 0 ) - { - if( cc[pid] != 0 ) - { - // TODO: 1 repetition allowed - if( ( ccin & 0x10 ) != 0 && (((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) ) - cc_errors += 1; - } - cc[pid] = ccin; - } - payload_packets += 1; - } - } - else - packet_errors += 1; - - if( (packets & 0x3FFF ) == 0) - { - printf("%s Packets: %12u non null %12u, errors: %12u, CC errors: %12u%s", line_start, packets, payload_packets, packet_errors, cc_errors, line_end); - fflush(stdout); - } - - packets += 1; + if (buf[0] == 0x47 && (buf[1] & 0x80) == 0) { + if( pid != 8191 ) { + if (ccin & 0x10) { + if ( cc[pid]) { + // TODO: 1 repetition allowed + if( ( ccin & 0x10 ) != 0 && (((cc[pid] + 1) & 0x0F) != (ccin & 0x0F)) ) + cc_errors += 1; + } + cc[pid] = ccin; + } + payload_packets += 1; + } + } else + packet_errors += 1; + + if( (packets & 0x3FFF ) == 0) + { + printf("%s Packets: %12u non null %12u, errors: %12u, CC errors: %12u%s", line_start, packets, payload_packets, packet_errors, cc_errors, line_end); + fflush(stdout); + } + + packets += 1; } #define TSBUFSIZE (100*188) @@ -108,6 +103,7 @@ int main(int argc, char **argv) uint32_t id = DDDVB_UNDEF, ssi = DDDVB_UNDEF, num = DDDVB_UNDEF, source = 0; uint32_t mtype= DDDVB_UNDEF; uint32_t verbosity = 0; + uint32_t get_ts = 1; enum fe_code_rate fec = FEC_AUTO; enum fe_delivery_system delsys = ~0; char *config = "config/"; @@ -137,11 +133,12 @@ int main(int argc, char **argv) {"open_dvr", no_argument, 0, 'o'}, {"tscheck", no_argument, 0, 't'}, {"tscheck_l", required_argument, 0, 'a'}, + {"nodvr", no_argument , 0, 'q'}, {"help", no_argument , 0, 'h'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, - "c:i:f:s:d:p:hg:r:n:b:l:v:m:ota:", + "c:i:f:s:d:p:hg:r:n:b:l:v:m:ota:q", long_options, &option_index); if (c==-1) break; @@ -245,6 +242,9 @@ int main(int argc, char **argv) if (!strcmp(optarg, "v") || !strcmp(optarg, "V")) pol = 0; break; + case 'q': + get_ts = 0; + break; case 'h': fprintf(fout,"ddzap [-d delivery_system] [-p polarity] [-c config_dir] [-f frequency(Hz)]\n" " [-b bandwidth(Hz)] [-s symbol_rate(Hz)]\n" @@ -283,6 +283,7 @@ int main(int argc, char **argv) exit(-1); } fprintf(fout,"dvbnum = %u\n", dd->dvbfe_num); + dddvb_get_ts(dd, get_ts); if (num != DDDVB_UNDEF) fe = dddvb_fe_alloc_num(dd, delsys, num); @@ -303,6 +304,7 @@ int main(int argc, char **argv) dddvb_set_id(&p, id); dddvb_set_ssi(&p, ssi); dddvb_dvb_tune(fe, &p); + #if 0 { uint8_t ts[188]; diff --git a/lib/src/dddvb.c b/lib/src/dddvb.c index 17af839..aa85a8b 100644 --- a/lib/src/dddvb.c +++ b/lib/src/dddvb.c @@ -89,6 +89,7 @@ LIBDDDVB_EXPORTED struct dddvb *dddvb_init(char *config, uint32_t flags) dddvb_dvb_init(dd); global_dd = dd; + dd->get_ts = 1; fail: pthread_mutex_unlock(&dddvb_mutex); return dd; diff --git a/lib/src/dddvb.h b/lib/src/dddvb.h index 545e877..f9e76d8 100644 --- a/lib/src/dddvb.h +++ b/lib/src/dddvb.h @@ -150,6 +150,9 @@ struct dddvb { struct dddvb_fe dvbfe[DDDVB_MAX_DVB_FE]; struct dddvb_ca dvbca[DDDVB_MAX_DVB_CA]; + + + unsigned int get_ts:1; }; int dddvb_dvb_init(struct dddvb *dd); diff --git a/lib/src/dvb.c b/lib/src/dvb.c index 618eb03..81a1ef7 100644 --- a/lib/src/dvb.c +++ b/lib/src/dvb.c @@ -531,7 +531,7 @@ static int tune(struct dddvb_fe *fe) return ret; } -static int open_dmx(struct dddvb_fe *fe) +int open_dmx(struct dddvb_fe *fe) { char fname[80]; struct dmx_pes_filter_params pesFilterParams; @@ -623,10 +623,9 @@ void dddvb_fe_handle(struct dddvb_fe *fe) uint32_t newtune, count = 0, max, nolock = 0; int ret; - printf("fe_handle\n"); - open_dmx(fe); - printf("fe_handle 2\n"); + if (fe->dd->get_ts) + open_dmx(fe); while (fe->state == 1) { pthread_mutex_lock(&fe->mutex); newtune = fe->n_tune; diff --git a/lib/src/libdddvb.h b/lib/src/libdddvb.h index f4c802d..3b28f6a 100644 --- a/lib/src/libdddvb.h +++ b/lib/src/libdddvb.h @@ -64,6 +64,9 @@ LIBDDDVB_EXPORTED int dddvb_ca_write(struct dddvb *dd, uint32_t nr, uint8_t *buf LIBDDDVB_EXPORTED int dddvb_ca_read(struct dddvb *dd, uint32_t nr, uint8_t *buf, uint32_t len); LIBDDDVB_EXPORTED int dddvb_ca_set_pmts(struct dddvb *dd, uint32_t nr, uint8_t **pmts); +static inline void dddvb_get_ts(struct dddvb *dd, uint32_t val) { + dd->get_ts = val; +}; static inline void dddvb_set_frequency(struct dddvb_params *p, uint32_t freq) { p->param[PARAM_FREQ] = freq; From ddac58d0829c6cb5c206c4d21129ac56a69c2ad2 Mon Sep 17 00:00:00 2001 From: none Date: Sat, 29 Aug 2020 14:57:02 +0200 Subject: [PATCH 35/55] add raw mode, selected either via module option or input parameter --- ddbridge/ddbridge-core.c | 16 +++++++++++++--- ddbridge/ddbridge-mci.c | 1 + ddbridge/ddbridge-mci.h | 1 + ddbridge/ddbridge-sx8.c | 9 ++++++--- ddbridge/ddbridge.h | 1 + 5 files changed, 22 insertions(+), 6 deletions(-) diff --git a/ddbridge/ddbridge-core.c b/ddbridge/ddbridge-core.c index 829e604..dd31347 100644 --- a/ddbridge/ddbridge-core.c +++ b/ddbridge/ddbridge-core.c @@ -56,6 +56,10 @@ static int xo2_speed = 2; module_param(xo2_speed, int, 0444); MODULE_PARM_DESC(xo2_speed, "default transfer speed for xo2 based duoflex, 0=55,1=75,2=90,3=104 MBit/s, default=2, use attribute to change for individual cards"); +static int raw_stream; +module_param(raw_stream, int, 0444); +MODULE_PARM_DESC(raw_stream, "send data as raw stream to DVB layer"); + #ifdef __arm__ static int alt_dma = 1; #else @@ -2401,9 +2405,15 @@ static void input_write_dvb(struct ddb_input *input, if (alt_dma) dma_sync_single_for_cpu(dev->dev, dma2->pbuf[dma->cbuf], dma2->size, DMA_FROM_DEVICE); - dvb_dmx_swfilter_packets(&dvb->demux, - dma2->vbuf[dma->cbuf], - dma2->size / 188); + if (raw_stream || input->con) + dvb_dmx_swfilter_raw(&dvb->demux, + dma2->vbuf[dma->cbuf], + dma2->size); + else + dvb_dmx_swfilter_packets(&dvb->demux, + dma2->vbuf[dma->cbuf], + dma2->size / 188); + dma->cbuf = (dma->cbuf + 1) % dma2->num; if (ack) ddbwritel(dev, (dma->cbuf << 11), diff --git a/ddbridge/ddbridge-mci.c b/ddbridge/ddbridge-mci.c index 9180592..a5683a0 100644 --- a/ddbridge/ddbridge-mci.c +++ b/ddbridge/ddbridge-mci.c @@ -388,6 +388,7 @@ struct dvb_frontend *ddb_mci_attach(struct ddb_input *input, struct mci_cfg *cfg state->nr = nr; state->demod = nr; state->tuner = tuner; + state->input = input; if (cfg->init) cfg->init(state); return &state->fe; diff --git a/ddbridge/ddbridge-mci.h b/ddbridge/ddbridge-mci.h index e03ccc6..a1b2fa9 100644 --- a/ddbridge/ddbridge-mci.h +++ b/ddbridge/ddbridge-mci.h @@ -759,6 +759,7 @@ struct mci_base { }; struct mci { + struct ddb_io *input; struct mci_base *base; struct dvb_frontend fe; int nr; diff --git a/ddbridge/ddbridge-sx8.c b/ddbridge/ddbridge-sx8.c index ab07ecd..9f4c017 100644 --- a/ddbridge/ddbridge-sx8.c +++ b/ddbridge/ddbridge-sx8.c @@ -354,7 +354,8 @@ unlock: cmd.tuner = state->mci.tuner; cmd.demod = state->mci.demod; cmd.output = state->mci.nr; - if (p->stream_id == 0x80000000) + if ((p->stream_id != NO_STREAM_ID_FILTER) && + (p->stream_id & 0x80000000)) cmd.output |= 0x80; stat = ddb_mci_cmd(&state->mci, &cmd, NULL); if (stat) @@ -426,13 +427,15 @@ static int set_parameters(struct dvb_frontend *fe) int stat = 0; struct sx8 *state = fe->demodulator_priv; struct dtv_frontend_properties *p = &fe->dtv_property_cache; - u32 ts_config = SX8_TSCONFIG_MODE_NORMAL, iq_mode = 0, isi; + u32 ts_config = SX8_TSCONFIG_MODE_NORMAL, iq_mode = 0, isi, ts_mode = 0; - isi = p->stream_id; if (isi != NO_STREAM_ID_FILTER) { iq_mode = (isi & 0x30000000) >> 28; + ts_mode = (isi & 0x03000000) >> 24; } + state->mci.input->con = ts_mode << 8; + printk("ts_mode = %02x\n", ts_mode); if (iq_mode) ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ); stop(fe); diff --git a/ddbridge/ddbridge.h b/ddbridge/ddbridge.h index ff35992..51f47cd 100644 --- a/ddbridge/ddbridge.h +++ b/ddbridge/ddbridge.h @@ -256,6 +256,7 @@ struct ddb_io { struct ddb_port *port; u32 nr; u32 regs; + u32 con; struct ddb_dma *dma; struct ddb_io *redo; struct ddb_io *redi; From 4747cbd55363ba374a1cd062211d94c2db9161da Mon Sep 17 00:00:00 2001 From: none Date: Sat, 29 Aug 2020 14:59:45 +0200 Subject: [PATCH 36/55] fix init --- ddbridge/ddbridge-modulator.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ddbridge/ddbridge-modulator.c b/ddbridge/ddbridge-modulator.c index f1c2cfd..e532bd5 100644 --- a/ddbridge/ddbridge-modulator.c +++ b/ddbridge/ddbridge-modulator.c @@ -435,7 +435,7 @@ static int mod_setup_max2871(struct ddb *dev, u32 *reg) if (j == 4) val &= 0xFFFFFEDF; - status = mod_write_max2871(dev, reg[j]); + status = mod_write_max2871(dev, val); if (status) break; msleep(30); @@ -1875,7 +1875,7 @@ static int rfdac_init(struct ddb *dev) } if (tmp & 0x80) return -1; - dev_info(dev->dev, "sync %d:%08x\n", i, tmp); + //dev_info(dev->dev, "sync %d:%08x\n", i, tmp); ddbwritel(dev, RFDAC_CMD_RESET, RFDAC_CONTROL); for (i = 0; i < 10; i++) { msleep(20); @@ -1885,7 +1885,7 @@ static int rfdac_init(struct ddb *dev) } if (tmp & 0x80) return -1; - dev_info(dev->dev, "sync %d:%08x\n", i, tmp); + //dev_info(dev->dev, "sync %d:%08x\n", i, tmp); ddbwritel(dev, RFDAC_CMD_SETUP, RFDAC_CONTROL); for (i = 0; i < 10; i++) { msleep(20); @@ -1895,7 +1895,7 @@ static int rfdac_init(struct ddb *dev) } if (tmp & 0x80) return -1; - dev_info(dev->dev, "sync %d:%08x\n", i, tmp); + //dev_info(dev->dev, "sync %d:%08x\n", i, tmp); ddbwritel(dev, 0x01, JESD204B_BASE); for (i = 0; i < 400; i++) { msleep(20); @@ -1903,7 +1903,7 @@ static int rfdac_init(struct ddb *dev) if ((tmp & 0xc0000000) == 0xc0000000) break; } - dev_info(dev->dev, "sync %d:%08x\n", i, tmp); + //dev_info(dev->dev, "sync %d:%08x\n", i, tmp); if ((tmp & 0xc0000000) != 0xc0000000) return -1; return 0; From dc300198a96b57fa9edd56c51c30d97a803523e3 Mon Sep 17 00:00:00 2001 From: none Date: Sat, 29 Aug 2020 15:18:59 +0200 Subject: [PATCH 37/55] rest of raw support ... --- ddbridge/ddbridge-core.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/ddbridge/ddbridge-core.c b/ddbridge/ddbridge-core.c index dd31347..9fe0e29 100644 --- a/ddbridge/ddbridge-core.c +++ b/ddbridge/ddbridge-core.c @@ -583,13 +583,16 @@ static void ddb_input_start_unlocked(struct ddb_input *input) } if (dev->link[0].info->type == DDB_OCTONET) ddbwritel(dev, 0x01, TS_CONTROL(input)); - else - ddbwritel(dev, 0x09, TS_CONTROL(input)); + else { + if (raw_stream) + ddbwritel(dev, 0x01 | ((raw_stream & 3) << 8), TS_CONTROL(input)); + else + ddbwritel(dev, 0x01 | input->con, TS_CONTROL(input)); + } if (input->port->type == DDB_TUNER_DUMMY) ddbwritel(dev, 0x000fff01, TS_CONTROL2(input)); - if (input->dma) { + if (input->dma) input->dma->running = 1; - } } static void ddb_input_start(struct ddb_input *input) From 83f5b45928aafb880250c954e596f64eb0c1f38b Mon Sep 17 00:00:00 2001 From: none Date: Sat, 29 Aug 2020 15:20:58 +0200 Subject: [PATCH 38/55] adapt to current mainline kernel version --- include/linux/dvb/audio.h | 44 +-------- include/linux/dvb/ca.h | 1 + include/linux/dvb/dmx.h | 99 ++++++++++++++++++- include/linux/dvb/frontend.h | 30 +++--- include/linux/dvb/net.h | 1 + include/linux/dvb/osd.h | 179 +++++++++++++++++++++-------------- include/linux/dvb/version.h | 1 + include/linux/dvb/video.h | 87 +++-------------- 8 files changed, 241 insertions(+), 201 deletions(-) diff --git a/include/linux/dvb/audio.h b/include/linux/dvb/audio.h index d47bccd..8b13808 100644 --- a/include/linux/dvb/audio.h +++ b/include/linux/dvb/audio.h @@ -1,5 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ /* - * audio.h + * audio.h - DEPRECATED MPEG-TS audio decoder API + * + * NOTE: should not be used on future drivers * * Copyright (C) 2000 Ralph Metzler * & Marcus Metzler @@ -51,7 +54,7 @@ typedef enum { typedef struct audio_mixer { unsigned int volume_left; unsigned int volume_right; - // what else do we need? bass, pass-through, ... +/* what else do we need? bass, pass-through, ... */ } audio_mixer_t; @@ -66,27 +69,6 @@ typedef struct audio_status { } audio_status_t; /* separate decoder hardware */ -typedef -struct audio_karaoke { /* if Vocal1 or Vocal2 are non-zero, they get mixed */ - int vocal1; /* into left and right t at 70% each */ - int vocal2; /* if both, Vocal1 and Vocal2 are non-zero, Vocal1 gets*/ - int melody; /* mixed into the left channel and */ - /* Vocal2 into the right channel at 100% each. */ - /* if Melody is non-zero, the melody channel gets mixed*/ -} audio_karaoke_t; /* into left and right */ - - -typedef __u16 audio_attributes_t; -/* bits: descr. */ -/* 15-13 audio coding mode (0=ac3, 2=mpeg1, 3=mpeg2ext, 4=LPCM, 6=DTS, */ -/* 12 multichannel extension */ -/* 11-10 audio type (0=not spec, 1=language included) */ -/* 9- 8 audio application mode (0=not spec, 1=karaoke, 2=surround) */ -/* 7- 6 Quantization / DRC (mpeg audio: 1=DRC exists)(lpcm: 0=16bit, */ -/* 5- 4 Sample frequency fs (0=48kHz, 1=96kHz) */ -/* 2- 0 number of audio channels (n+1 channels) */ - - /* for GET_CAPABILITIES and SET_FORMAT, the latter should only set one bit */ #define AUDIO_CAP_DTS 1 #define AUDIO_CAP_LPCM 2 @@ -114,22 +96,6 @@ typedef __u16 audio_attributes_t; #define AUDIO_SET_ID _IO('o', 13) #define AUDIO_SET_MIXER _IOW('o', 14, audio_mixer_t) #define AUDIO_SET_STREAMTYPE _IO('o', 15) -#define AUDIO_SET_EXT_ID _IO('o', 16) -#define AUDIO_SET_ATTRIBUTES _IOW('o', 17, audio_attributes_t) -#define AUDIO_SET_KARAOKE _IOW('o', 18, audio_karaoke_t) - -/** - * AUDIO_GET_PTS - * - * Read the 33 bit presentation time stamp as defined - * in ITU T-REC-H.222.0 / ISO/IEC 13818-1. - * - * The PTS should belong to the currently played - * frame if possible, but may also be a value close to it - * like the PTS of the last decoded frame or the last PTS - * extracted by the PES parser. - */ -#define AUDIO_GET_PTS _IOR('o', 19, __u64) #define AUDIO_BILINGUAL_CHANNEL_SELECT _IO('o', 20) #endif /* _DVBAUDIO_H_ */ diff --git a/include/linux/dvb/ca.h b/include/linux/dvb/ca.h index 709fd3c..4c332e1 100644 --- a/include/linux/dvb/ca.h +++ b/include/linux/dvb/ca.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ /* * ca.h * diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h index 4aa5f6a..b4112f0 100644 --- a/include/linux/dvb/dmx.h +++ b/include/linux/dvb/dmx.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ /* * dmx.h * @@ -210,6 +211,96 @@ struct dmx_stc { __u64 stc; }; +/** + * enum dmx_buffer_flags - DMX memory-mapped buffer flags + * + * @DMX_BUFFER_FLAG_HAD_CRC32_DISCARD: + * Indicates that the Kernel discarded one or more frames due to wrong + * CRC32 checksum. + * @DMX_BUFFER_FLAG_TEI: + * Indicates that the Kernel has detected a Transport Error indicator + * (TEI) on a filtered pid. + * @DMX_BUFFER_PKT_COUNTER_MISMATCH: + * Indicates that the Kernel has detected a packet counter mismatch + * on a filtered pid. + * @DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED: + * Indicates that the Kernel has detected one or more frame discontinuity. + * @DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR: + * Received at least one packet with a frame discontinuity indicator. + */ + +enum dmx_buffer_flags { + DMX_BUFFER_FLAG_HAD_CRC32_DISCARD = 1 << 0, + DMX_BUFFER_FLAG_TEI = 1 << 1, + DMX_BUFFER_PKT_COUNTER_MISMATCH = 1 << 2, + DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED = 1 << 3, + DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR = 1 << 4, +}; + +/** + * struct dmx_buffer - dmx buffer info + * + * @index: id number of the buffer + * @bytesused: number of bytes occupied by data in the buffer (payload); + * @offset: for buffers with memory == DMX_MEMORY_MMAP; + * offset from the start of the device memory for this plane, + * (or a "cookie" that should be passed to mmap() as offset) + * @length: size in bytes of the buffer + * @flags: bit array of buffer flags as defined by &enum dmx_buffer_flags. + * Filled only at &DMX_DQBUF. + * @count: monotonic counter for filled buffers. Helps to identify + * data stream loses. Filled only at &DMX_DQBUF. + * + * Contains data exchanged by application and driver using one of the streaming + * I/O methods. + * + * Please notice that, for &DMX_QBUF, only @index should be filled. + * On &DMX_DQBUF calls, all fields will be filled by the Kernel. + */ +struct dmx_buffer { + __u32 index; + __u32 bytesused; + __u32 offset; + __u32 length; + __u32 flags; + __u32 count; +}; + +/** + * struct dmx_requestbuffers - request dmx buffer information + * + * @count: number of requested buffers, + * @size: size in bytes of the requested buffer + * + * Contains data used for requesting a dmx buffer. + * All reserved fields must be set to zero. + */ +struct dmx_requestbuffers { + __u32 count; + __u32 size; +}; + +/** + * struct dmx_exportbuffer - export of dmx buffer as DMABUF file descriptor + * + * @index: id number of the buffer + * @flags: flags for newly created file, currently only O_CLOEXEC is + * supported, refer to manual of open syscall for more details + * @fd: file descriptor associated with DMABUF (set by driver) + * + * Contains data used for exporting a dmx buffer as DMABUF file descriptor. + * The buffer is identified by a 'cookie' returned by DMX_QUERYBUF + * (identical to the cookie used to mmap() the buffer to userspace). All + * reserved fields must be set to zero. The field reserved0 is expected to + * become a structure 'type' allowing an alternative layout of the structure + * content. Therefore this field should not be used for any other extensions. + */ +struct dmx_exportbuffer { + __u32 index; + __u32 flags; + __s32 fd; +}; + #define DMX_START _IO('o', 41) #define DMX_STOP _IO('o', 42) #define DMX_SET_FILTER _IOW('o', 43, struct dmx_sct_filter_params) @@ -230,4 +321,10 @@ typedef struct dmx_filter dmx_filter_t; #endif -#endif /* _UAPI_DVBDMX_H_ */ +#define DMX_REQBUFS _IOWR('o', 60, struct dmx_requestbuffers) +#define DMX_QUERYBUF _IOWR('o', 61, struct dmx_buffer) +#define DMX_EXPBUF _IOWR('o', 62, struct dmx_exportbuffer) +#define DMX_QBUF _IOWR('o', 63, struct dmx_buffer) +#define DMX_DQBUF _IOWR('o', 64, struct dmx_buffer) + +#endif /* _DVBDMX_H_ */ diff --git a/include/linux/dvb/frontend.h b/include/linux/dvb/frontend.h index c9d2e14..a624d90 100644 --- a/include/linux/dvb/frontend.h +++ b/include/linux/dvb/frontend.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ /* * frontend.h * @@ -769,16 +770,15 @@ enum fecap_scale_params { /** * struct dtv_stats - Used for reading a DTV status property * - * @scale: Filled with enum fecap_scale_params - the scale - * in usage for that parameter + * @scale: + * Filled with enum fecap_scale_params - the scale in usage + * for that parameter * - * The ``{unnamed_union}`` may have either one of the values below: - * - * %svalue + * @svalue: * integer value of the measure, for %FE_SCALE_DECIBEL, * used for dB measures. The unit is 0.001 dB. * - * %uvalue + * @uvalue: * unsigned integer value of the measure, used when @scale is * either %FE_SCALE_RELATIVE or %FE_SCALE_COUNTER. * @@ -844,16 +844,16 @@ struct dtv_fe_stats { * @cmd: Digital TV command. * @reserved: Not used. * @u: Union with the values for the command. - * @result: Result of the command set (currently unused). + * @u.data: A unsigned 32 bits integer with command value. + * @u.buffer: Struct to store bigger properties. + * Currently unused. + * @u.buffer.data: an unsigned 32-bits array. + * @u.buffer.len: number of elements of the buffer. + * @u.buffer.reserved1: Reserved. + * @u.buffer.reserved2: Reserved. + * @u.st: a &struct dtv_fe_stats array of statistics. + * @result: Currently unused. * - * The @u union may have either one of the values below: - * - * %data - * an unsigned 32-bits number. - * %st - * a &struct dtv_fe_stats array of statistics. - * %buffer - * a buffer of up to 32 characters (currently unused). */ struct dtv_property { __u32 cmd; diff --git a/include/linux/dvb/net.h b/include/linux/dvb/net.h index 89d805f..0c550ef 100644 --- a/include/linux/dvb/net.h +++ b/include/linux/dvb/net.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ /* * net.h * diff --git a/include/linux/dvb/osd.h b/include/linux/dvb/osd.h index 6a295fa..858997c 100644 --- a/include/linux/dvb/osd.h +++ b/include/linux/dvb/osd.h @@ -1,5 +1,8 @@ +/* SPDX-License-Identifier: LGPL-2.1+ WITH Linux-syscall-note */ /* - * osd.h + * osd.h - DEPRECATED On Screen Display API + * + * NOTE: should not be used on future drivers * * Copyright (C) 2001 Ralph Metzler * & Marcus Metzler @@ -26,79 +29,109 @@ #include -#ifndef __user -#define __user -#endif - typedef enum { - // All functions return -2 on "not open" - OSD_Close=1, // () - // Disables OSD and releases the buffers - // returns 0 on success - OSD_Open, // (x0,y0,x1,y1,BitPerPixel[2/4/8](color&0x0F),mix[0..15](color&0xF0)) - // Opens OSD with this size and bit depth - // returns 0 on success, -1 on DRAM allocation error, -2 on "already open" - OSD_Show, // () - // enables OSD mode - // returns 0 on success - OSD_Hide, // () - // disables OSD mode - // returns 0 on success - OSD_Clear, // () - // Sets all pixel to color 0 - // returns 0 on success - OSD_Fill, // (color) - // Sets all pixel to color - // returns 0 on success - OSD_SetColor, // (color,R{x0},G{y0},B{x1},opacity{y1}) - // set palette entry to , and apply - // R,G,B: 0..255 - // R=Red, G=Green, B=Blue - // opacity=0: pixel opacity 0% (only video pixel shows) - // opacity=1..254: pixel opacity as specified in header - // opacity=255: pixel opacity 100% (only OSD pixel shows) - // returns 0 on success, -1 on error - OSD_SetPalette, // (firstcolor{color},lastcolor{x0},data) - // Set a number of entries in the palette - // sets the entries "firstcolor" through "lastcolor" from the array "data" - // data has 4 byte for each color: - // R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel - OSD_SetTrans, // (transparency{color}) - // Sets transparency of mixed pixel (0..15) - // returns 0 on success - OSD_SetPixel, // (x0,y0,color) - // sets pixel , to color number - // returns 0 on success, -1 on error - OSD_GetPixel, // (x0,y0) - // returns color number of pixel ,, or -1 - OSD_SetRow, // (x0,y0,x1,data) - // fills pixels x0,y through x1,y with the content of data[] - // returns 0 on success, -1 on clipping all pixel (no pixel drawn) - OSD_SetBlock, // (x0,y0,x1,y1,increment{color},data) - // fills pixels x0,y0 through x1,y1 with the content of data[] - // inc contains the width of one line in the data block, - // inc<=0 uses blockwidth as linewidth - // returns 0 on success, -1 on clipping all pixel - OSD_FillRow, // (x0,y0,x1,color) - // fills pixels x0,y through x1,y with the color - // returns 0 on success, -1 on clipping all pixel - OSD_FillBlock, // (x0,y0,x1,y1,color) - // fills pixels x0,y0 through x1,y1 with the color - // returns 0 on success, -1 on clipping all pixel - OSD_Line, // (x0,y0,x1,y1,color) - // draw a line from x0,y0 to x1,y1 with the color - // returns 0 on success - OSD_Query, // (x0,y0,x1,y1,xasp{color}}), yasp=11 - // fills parameters with the picture dimensions and the pixel aspect ratio - // returns 0 on success - OSD_Test, // () - // draws a test picture. for debugging purposes only - // returns 0 on success -// TODO: remove "test" in final version - OSD_Text, // (x0,y0,size,color,text) - OSD_SetWindow, // (x0) set window with number 0 + * returns 0 on success + */ + OSD_SetColor, /* (color,R{x0},G{y0},B{x1},opacity{y1}) */ + /* + * set palette entry to , and apply + * R,G,B: 0..255 + * R=Red, G=Green, B=Blue + * opacity=0: pixel opacity 0% (only video pixel shows) + * opacity=1..254: pixel opacity as specified in header + * opacity=255: pixel opacity 100% (only OSD pixel shows) + * returns 0 on success, -1 on error + */ + OSD_SetPalette, /* (firstcolor{color},lastcolor{x0},data) */ + /* + * Set a number of entries in the palette + * sets the entries "firstcolor" through "lastcolor" from the array "data" + * data has 4 byte for each color: + * R,G,B, and a opacity value: 0->transparent, 1..254->mix, 255->pixel + */ + OSD_SetTrans, /* (transparency{color}) */ + /* + * Sets transparency of mixed pixel (0..15) + * returns 0 on success + */ + OSD_SetPixel, /* (x0,y0,color) */ + /* + * sets pixel , to color number + * returns 0 on success, -1 on error + */ + OSD_GetPixel, /* (x0,y0) */ + /* returns color number of pixel ,, or -1 */ + OSD_SetRow, /* (x0,y0,x1,data) */ + /* + * fills pixels x0,y through x1,y with the content of data[] + * returns 0 on success, -1 on clipping all pixel (no pixel drawn) + */ + OSD_SetBlock, /* (x0,y0,x1,y1,increment{color},data) */ + /* + * fills pixels x0,y0 through x1,y1 with the content of data[] + * inc contains the width of one line in the data block, + * inc<=0 uses blockwidth as linewidth + * returns 0 on success, -1 on clipping all pixel + */ + OSD_FillRow, /* (x0,y0,x1,color) */ + /* + * fills pixels x0,y through x1,y with the color + * returns 0 on success, -1 on clipping all pixel + */ + OSD_FillBlock, /* (x0,y0,x1,y1,color) */ + /* + * fills pixels x0,y0 through x1,y1 with the color + * returns 0 on success, -1 on clipping all pixel + */ + OSD_Line, /* (x0,y0,x1,y1,color) */ + /* + * draw a line from x0,y0 to x1,y1 with the color + * returns 0 on success + */ + OSD_Query, /* (x0,y0,x1,y1,xasp{color}}), yasp=11 */ + /* + * fills parameters with the picture dimensions and the pixel aspect ratio + * returns 0 on success + */ + OSD_Test, /* () */ + /* + * draws a test picture. for debugging purposes only + * returns 0 on success + * TODO: remove "test" in final version + */ + OSD_Text, /* (x0,y0,size,color,text) */ + OSD_SetWindow, /* (x0) set window with number 0 * & Ralph Metzler @@ -29,10 +32,6 @@ #include #endif -#ifndef __user -#define __user -#endif - typedef enum { VIDEO_FORMAT_4_3, /* Select 4:3 format */ VIDEO_FORMAT_16_9, /* Select 16:9 format. */ @@ -40,18 +39,6 @@ typedef enum { } video_format_t; -typedef enum { - VIDEO_SYSTEM_PAL, - VIDEO_SYSTEM_NTSC, - VIDEO_SYSTEM_PALN, - VIDEO_SYSTEM_PALNc, - VIDEO_SYSTEM_PALM, - VIDEO_SYSTEM_NTSC60, - VIDEO_SYSTEM_PAL60, - VIDEO_SYSTEM_PALM60 -} video_system_t; - - typedef enum { VIDEO_PAN_SCAN, /* use pan and scan format */ VIDEO_LETTER_BOX, /* use letterbox format */ @@ -86,11 +73,11 @@ typedef enum { #define VIDEO_CMD_CONTINUE (3) /* Flags for VIDEO_CMD_FREEZE */ -#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0) +#define VIDEO_CMD_FREEZE_TO_BLACK (1 << 0) /* Flags for VIDEO_CMD_STOP */ -#define VIDEO_CMD_STOP_TO_BLACK (1 << 0) -#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1) +#define VIDEO_CMD_STOP_TO_BLACK (1 << 0) +#define VIDEO_CMD_STOP_IMMEDIATELY (1 << 1) /* Play input formats: */ /* The decoder has no special format requirements */ @@ -127,8 +114,8 @@ struct video_command { /* FIELD_UNKNOWN can be used if the hardware does not know whether the Vsync is for an odd, even or progressive (i.e. non-interlaced) field. */ -#define VIDEO_VSYNC_FIELD_UNKNOWN (0) -#define VIDEO_VSYNC_FIELD_ODD (1) +#define VIDEO_VSYNC_FIELD_UNKNOWN (0) +#define VIDEO_VSYNC_FIELD_ODD (1) #define VIDEO_VSYNC_FIELD_EVEN (2) #define VIDEO_VSYNC_FIELD_PROGRESSIVE (3) @@ -136,8 +123,8 @@ struct video_event { __s32 type; #define VIDEO_EVENT_SIZE_CHANGED 1 #define VIDEO_EVENT_FRAME_RATE_CHANGED 2 -#define VIDEO_EVENT_DECODER_STOPPED 3 -#define VIDEO_EVENT_VSYNC 4 +#define VIDEO_EVENT_DECODER_STOPPED 3 +#define VIDEO_EVENT_VSYNC 4 /* unused, make sure to use atomic time for y2038 if it ever gets used */ long timestamp; union { @@ -163,44 +150,6 @@ struct video_still_picture { }; -typedef -struct video_highlight { - int active; /* 1=show highlight, 0=hide highlight */ - __u8 contrast1; /* 7- 4 Pattern pixel contrast */ - /* 3- 0 Background pixel contrast */ - __u8 contrast2; /* 7- 4 Emphasis pixel-2 contrast */ - /* 3- 0 Emphasis pixel-1 contrast */ - __u8 color1; /* 7- 4 Pattern pixel color */ - /* 3- 0 Background pixel color */ - __u8 color2; /* 7- 4 Emphasis pixel-2 color */ - /* 3- 0 Emphasis pixel-1 color */ - __u32 ypos; /* 23-22 auto action mode */ - /* 21-12 start y */ - /* 9- 0 end y */ - __u32 xpos; /* 23-22 button color number */ - /* 21-12 start x */ - /* 9- 0 end x */ -} video_highlight_t; - - -typedef struct video_spu { - int active; - int stream_id; -} video_spu_t; - - -typedef struct video_spu_palette { /* SPU Palette information */ - int length; - __u8 __user *palette; -} video_spu_palette_t; - - -typedef struct video_navi_pack { - int length; /* 0 ... 1024 */ - __u8 data[1024]; -} video_navi_pack_t; - - typedef __u16 video_attributes_t; /* bits: descr. */ /* 15-14 Video compression mode (0=MPEG-1, 1=MPEG-2) */ @@ -245,17 +194,9 @@ typedef __u16 video_attributes_t; #define VIDEO_SLOWMOTION _IO('o', 32) #define VIDEO_GET_CAPABILITIES _IOR('o', 33, unsigned int) #define VIDEO_CLEAR_BUFFER _IO('o', 34) -#define VIDEO_SET_ID _IO('o', 35) #define VIDEO_SET_STREAMTYPE _IO('o', 36) #define VIDEO_SET_FORMAT _IO('o', 37) -#define VIDEO_SET_SYSTEM _IO('o', 38) -#define VIDEO_SET_HIGHLIGHT _IOW('o', 39, video_highlight_t) -#define VIDEO_SET_SPU _IOW('o', 50, video_spu_t) -#define VIDEO_SET_SPU_PALETTE _IOW('o', 51, video_spu_palette_t) -#define VIDEO_GET_NAVI _IOR('o', 52, video_navi_pack_t) -#define VIDEO_SET_ATTRIBUTES _IO('o', 53) #define VIDEO_GET_SIZE _IOR('o', 55, video_size_t) -#define VIDEO_GET_FRAME_RATE _IOR('o', 56, unsigned int) /** * VIDEO_GET_PTS @@ -271,9 +212,9 @@ typedef __u16 video_attributes_t; #define VIDEO_GET_PTS _IOR('o', 57, __u64) /* Read the number of displayed frames since the decoder was started */ -#define VIDEO_GET_FRAME_COUNT _IOR('o', 58, __u64) +#define VIDEO_GET_FRAME_COUNT _IOR('o', 58, __u64) -#define VIDEO_COMMAND _IOWR('o', 59, struct video_command) -#define VIDEO_TRY_COMMAND _IOWR('o', 60, struct video_command) +#define VIDEO_COMMAND _IOWR('o', 59, struct video_command) +#define VIDEO_TRY_COMMAND _IOWR('o', 60, struct video_command) #endif /* _UAPI_DVBVIDEO_H_ */ From 7f19a0c04b893edf4a7f7a23ca98c7c20d4af639 Mon Sep 17 00:00:00 2001 From: none Date: Sat, 29 Aug 2020 15:32:42 +0200 Subject: [PATCH 39/55] adapt to current mainline kernel dvb-core --- Makefile | 10 +- ddbridge/Kbuild | 10 +- ddbridge/Makefile | 9 +- ddbridge/ddbridge-ci.c | 2 +- ddbridge/ddbridge-core.c | 244 +--- ddbridge/ddbridge-hw.c | 6 +- ddbridge/ddbridge-i2c.c | 43 +- ddbridge/ddbridge-i2c.h | 2 +- ddbridge/ddbridge-io.c | 1 + ddbridge/ddbridge-io.h | 3 +- ddbridge/ddbridge-m4.c | 29 +- ddbridge/ddbridge-main.c | 10 +- ddbridge/ddbridge-max.c | 8 +- ddbridge/ddbridge-mci.c | 38 +- ddbridge/ddbridge-mci.h | 16 +- ddbridge/ddbridge-ns.c | 4 +- ddbridge/ddbridge-sx8.c | 10 +- ddbridge/ddbridge.h | 22 +- ddbridge/dvb_netstream.h | 2 +- dvb-core/Kconfig | 41 +- dvb-core/Makefile | 9 +- dvb-core/Makefile.kernel | 2 + dvb-core/dmxdev.c | 324 +++++- dvb-core/dmxdev.h | 115 -- dvb-core/dvb_ca_en50221.c | 4 +- dvb-core/dvb_demux.c | 172 ++- dvb-core/dvb_demux.h | 145 --- dvb-core/dvb_frontend.c | 1029 +++++++++++------ dvb-core/dvb_math.c | 2 +- dvb-core/dvb_net.c | 110 +- dvb-core/dvb_ringbuffer.c | 4 +- dvb-core/dvbdev.c | 160 ++- frontends/Makefile | 1 - frontends/cxd2099.h | 2 +- frontends/cxd2843.c | 36 +- frontends/drxk_hard.c | 37 +- frontends/lnbh25.c | 2 +- frontends/lnbp21.c | 2 +- frontends/mxl5xx.c | 13 +- frontends/stv0367dd.c | 8 +- frontends/stv090x.c | 10 +- frontends/stv090x_priv.h | 2 +- frontends/stv0910.c | 12 +- frontends/stv6110x.c | 10 +- frontends/stv6111.c | 8 +- frontends/tda18212dd.c | 8 +- frontends/tda18271c2dd.c | 11 +- {dvb-core => include/linux/media}/demux.h | 21 +- include/linux/media/dmxdev.h | 220 ++++ .../linux/media}/dvb_ca_en50221.h | 2 +- include/linux/media/dvb_demux.h | 354 ++++++ .../linux/media}/dvb_filter.h | 0 .../linux/media}/dvb_frontend.h | 214 ++-- {dvb-core => include/linux/media}/dvb_math.h | 0 {dvb-core => include/linux/media}/dvb_net.h | 36 +- .../linux/media}/dvb_ringbuffer.h | 0 include/linux/media/dvb_vb2.h | 280 +++++ {dvb-core => include/linux/media}/dvbdev.h | 224 +++- 58 files changed, 2708 insertions(+), 1391 deletions(-) delete mode 100644 dvb-core/dmxdev.h delete mode 100644 dvb-core/dvb_demux.h rename {dvb-core => include/linux/media}/demux.h (97%) create mode 100644 include/linux/media/dmxdev.h rename {dvb-core => include/linux/media}/dvb_ca_en50221.h (99%) create mode 100644 include/linux/media/dvb_demux.h rename {dvb-core => include/linux/media}/dvb_filter.h (100%) rename {dvb-core => include/linux/media}/dvb_frontend.h (83%) rename {dvb-core => include/linux/media}/dvb_math.h (100%) rename {dvb-core => include/linux/media}/dvb_net.h (56%) rename {dvb-core => include/linux/media}/dvb_ringbuffer.h (100%) create mode 100644 include/linux/media/dvb_vb2.h rename {dvb-core => include/linux/media}/dvbdev.h (59%) diff --git a/Makefile b/Makefile index 6401060..28c954a 100644 --- a/Makefile +++ b/Makefile @@ -2,10 +2,15 @@ kernelver ?= $(shell uname -r) KDIR ?= /lib/modules/$(kernelver)/build PWD := $(shell pwd) -MODDEFS := CONFIG_DVB_CORE=m CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_DRXK=m CONFIG_DVB_TDA18271C2DD=m CONFIG_DVB_CXD2099=m CONFIG_DVB_LNBP21=m CONFIG_DVB_STV090x=m CONFIG_DVB_STV6110x=m CONFIG_DVB_STV0367=m CONFIG_DVB_TDA18212=m CONFIG_DVB_STV0367DD=m CONFIG_DVB_TDA18212DD=m CONFIG_DVB_OCTONET=m CONFIG_DVB_CXD2843=m CONFIG_DVB_STV0910=m CONFIG_DVB_STV6111=m CONFIG_DVB_LNBH25=m CONFIG_DVB_MXL5XX=m CONFIG_DVB_NET=m +MODDEFS := CONFIG_DVB_CORE=m CONFIG_DVB_DDBRIDGE=m CONFIG_DVB_DRXK=m CONFIG_DVB_TDA18271C2DD=m CONFIG_DVB_CXD2099=m CONFIG_DVB_LNBP21=m CONFIG_DVB_STV090x=m CONFIG_DVB_STV6110x=m CONFIG_DVB_STV0367=m CONFIG_DVB_TDA18212=m CONFIG_DVB_STV0367DD=m CONFIG_DVB_TDA18212DD=m CONFIG_DVB_OCTONET=m CONFIG_DVB_CXD2843=m CONFIG_DVB_STV0910=m CONFIG_DVB_STV6111=m CONFIG_DVB_LNBH25=m CONFIG_DVB_MXL5XX=m CONFIG_DVB_NET=y DDDVB=y + +KBUILD_EXTMOD = $(PWD) + +DDDVB_INC = "-I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux -I$(KBUILD_EXTMOD)/frontends" + all: - $(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) $(MODDEFS) modules + $(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) $(MODDEFS) modules NOSTDINC_FLAGS=$(DDDVB_INC) $(MAKE) -C apps libdddvb: @@ -22,6 +27,7 @@ dep: install: all $(MAKE) -C $(KDIR) KBUILD_EXTMOD=$(PWD) modules_install + depmod -a clean: rm -rf */.*.o.d */*.o */*.ko */*.mod.c */.*.cmd .tmp_versions Module* modules* diff --git a/ddbridge/Kbuild b/ddbridge/Kbuild index 7cce364..bc9c7c5 100644 --- a/ddbridge/Kbuild +++ b/ddbridge/Kbuild @@ -3,9 +3,11 @@ EXTRA_CFLAGS += -DCONFIG_DVB_CXD2843 -DCONFIG_DVB_LNBP21 -DCONFIG_DVB_STV090x -D ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-io.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o -obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o +#mci-objs = ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o ddbridge-io.o + +obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o #mci.o obj-$(CONFIG_DVB_OCTONET) += octonet.o -EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends -EXTRA_CFLAGS += -Idrivers/media/common/tuners -NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core \ No newline at end of file +#EXTRA_CFLAGS += -Idrivers/media/dvb/frontends -Idrivers/media/dvb-frontends +#EXTRA_CFLAGS += -Idrivers/media/common/tuners +#NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/frontends -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core \ No newline at end of file diff --git a/ddbridge/Makefile b/ddbridge/Makefile index 1b286e2..f67e85b 100644 --- a/ddbridge/Makefile +++ b/ddbridge/Makefile @@ -1,14 +1,15 @@ # # Makefile for the ddbridge device driver # +#NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux -I$(KBUILD_EXTMOD)/dvb-frontends -I$(KBUILD_EXTMOD)/tuners ddbridge-objs = ddbridge-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o octonet-objs = octonet-main.o ddbridge-hw.o ddbridge-i2c.o ddbridge-ns.o ddbridge-modulator.o ddbridge-core.o ddbridge-ci.o ddbridge-max.o ddbridge-mci.o ddbridge-sx8.o ddbridge-m4.o dvb_netstream.o obj-$(CONFIG_DVB_DDBRIDGE) += ddbridge.o + obj-$(CONFIG_DVB_OCTONET) += octonet.o -ccflags-y += -Idrivers/media/dvb-core/ -ccflags-y += -Idrivers/media/dvb-frontends/ -ccflags-y += -Idrivers/media/tuners/ - +#ccflags-y += -Idrivers/media/include/linux/ +#ccflags-y += -Idrivers/media/dvb-frontends/ +#ccflags-y += -Idrivers/media/tuners/ diff --git a/ddbridge/ddbridge-ci.c b/ddbridge/ddbridge-ci.c index a0cd6d8..99d5a1f 100644 --- a/ddbridge/ddbridge-ci.c +++ b/ddbridge/ddbridge-ci.c @@ -329,7 +329,7 @@ int ddb_ci_attach(struct ddb_port *port, u32 bitrate) case DDB_CI_EXTERNAL_XO2_B: ci_xo2_attach(port); break; - + case DDB_CI_INTERNAL: ci_attach(port); break; diff --git a/ddbridge/ddbridge-core.c b/ddbridge/ddbridge-core.c index 9fe0e29..d911837 100644 --- a/ddbridge/ddbridge-core.c +++ b/ddbridge/ddbridge-core.c @@ -24,7 +24,7 @@ #include "ddbridge.h" #include "ddbridge-i2c.h" #include "ddbridge-io.h" -#include "dvb_net.h" +#include struct workqueue_struct *ddb_wq; @@ -103,6 +103,7 @@ struct ddb_irq *ddb_irq_set(struct ddb *dev, u32 link, u32 nr, irq->data = data; return irq; } +EXPORT_SYMBOL(ddb_irq_set); static void ddb_set_dma_table(struct ddb_io *io) { @@ -486,9 +487,8 @@ static void ddb_output_start_unlocked(struct ddb_output *output) } if (output->port->class != DDB_PORT_MOD) ddbwritel(dev, con | 1, TS_CONTROL(output)); - if (output->dma) { + if (output->dma) output->dma->running = 1; - } } static void ddb_output_start(struct ddb_output *output) @@ -669,7 +669,7 @@ static u32 ddb_output_free(struct ddb_output *output) if (output->dma->cbuf != idx) { if ((((output->dma->cbuf + 1) % output->dma->num) == idx) && - (output->dma->size - output->dma->coff <= 2*188)) + (output->dma->size - output->dma->coff <= 2 * 188)) return 0; return 188; } @@ -679,25 +679,6 @@ static u32 ddb_output_free(struct ddb_output *output) return 0; } -#if 0 -static u32 ddb_dma_free(struct ddb_dma *dma) -{ - u32 idx, off, stat = dma->stat; - s32 p1, p2, diff; - - idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; - - p1 = idx * dma->size + off; - p2 = dma->cbuf * dma->size + dma->coff; - - diff = p1 - p2; - if (diff <= 0) - diff += dma->num * dma->size; - return diff; -} -#endif - static ssize_t ddb_output_write(struct ddb_output *output, const __user u8 *buf, size_t count) { @@ -753,79 +734,6 @@ static ssize_t ddb_output_write(struct ddb_output *output, return count - left; } -#if 0 -static u32 ddb_input_free_bytes(struct ddb_input *input) -{ - struct ddb *dev = input->port->dev; - u32 idx, off, stat = input->dma->stat; - u32 ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(input->dma)); - - idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; - - if (ctrl & 4) - return 0; - if (input->dma->cbuf != idx) - return 1; - return 0; -} - -static s32 ddb_output_used_bufs(struct ddb_output *output) -{ - u32 idx, off, stat, ctrl; - s32 diff; - - spin_lock_irq(&output->dma->lock); - stat = output->dma->stat; - ctrl = output->dma->ctrl; - spin_unlock_irq(&output->dma->lock); - - idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; - - if (ctrl & 4) - return 0; - diff = output->dma->cbuf - idx; - if (diff == 0 && off < output->dma->coff) - return 0; - if (diff <= 0) - diff += output->dma->num; - return diff; -} - -static s32 ddb_input_free_bufs(struct ddb_input *input) -{ - u32 idx, off, stat, ctrl; - s32 free; - - spin_lock_irq(&input->dma->lock); - ctrl = input->dma->ctrl; - stat = input->dma->stat; - spin_unlock_irq(&input->dma->lock); - if (ctrl & 4) - return 0; - idx = (stat >> 11) & 0x1f; - off = (stat & 0x7ff) << 7; - free = input->dma->cbuf - idx; - if (free == 0 && off < input->dma->coff) - return 0; - if (free <= 0) - free += input->dma->num; - return free - 1; -} - -static u32 ddb_output_ok(struct ddb_output *output) -{ - struct ddb_input *input = output->port->input[0]; - s32 diff; - - diff = ddb_input_free_bufs(input) - ddb_output_used_bufs(output); - if (diff > 0) - return 1; - return 0; -} -#endif - static u32 ddb_input_avail(struct ddb_input *input) { struct ddb *dev = input->port->dev; @@ -1125,20 +1033,20 @@ static struct dvb_frontend_ops dummy_ops = { .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBS, SYS_DVBS2 }, .info = { .name = "DUMMY DVB-C/C2 DVB-T/T2", - .frequency_stepsize = 166667, /* DVB-T only */ - .frequency_min = 47000000, /* DVB-T: 47125000 */ - .frequency_max = 865000000, /* DVB-C: 862000000 */ + .frequency_stepsize_hz = 166667, /* DVB-T only */ + .frequency_min_hz = 47000000, /* DVB-T: 47125000 */ + .frequency_max_hz = 865000000, /* DVB-C: 862000000 */ .symbol_rate_min = 870000, .symbol_rate_max = 11700000, .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | - FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | - FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION + FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION }, .release = dummy_release, .read_status = dummy_read_status, @@ -1484,29 +1392,6 @@ static int tuner_attach_stv6111(struct ddb_input *input, int type) return 0; } -#if 0 -static int start_input(struct ddb_input *input) -{ - struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; - - if (!dvb->users) - ddb_input_start_all(input); - - return ++dvb->users; -} - -static int stop_input(struct ddb_input *input) -{ - struct ddb_dvb *dvb = &input->port->dvb[input->nr & 1]; - - if (--dvb->users) - return dvb->users; - - ddb_input_stop_all(input); - return 0; -} -#endif - static int start_feed(struct dvb_demux_feed *dvbdmxfeed) { struct dvb_demux *dvbdmx = dvbdmxfeed->demux; @@ -1603,7 +1488,7 @@ static int dvb_register_adapters(struct ddb *dev) if (adapter_alloc >= 3 || dev->link[0].info->type == DDB_MOD || dev->link[0].info->type == DDB_OCTONET || - dev->link[0].info->type == DDB_OCTOPRO ) { + dev->link[0].info->type == DDB_OCTOPRO) { port = &dev->port[0]; adap = port->dvb[0].adap; ret = dvb_register_adapter(adap, "DDBridge", THIS_MODULE, @@ -2118,16 +2003,6 @@ static void ddb_port_probe(struct ddb_port *port) port->class = DDB_PORT_MOD; return; } -#if 0 - if (link->info->type == DDB_OCTOPRO_HDIN) { - if (port->nr == 0) { - dev->link[l].info->type = DDB_OCTOPUS; - port->name = "HDIN"; - port->class = DDB_PORT_LOOP; - } - return; - } -#endif if (link->info->type == DDB_OCTOPUS_MAX) { port->name = "DUAL DVB-S2 MAX"; port->type_name = "MXL5XX"; @@ -2286,7 +2161,7 @@ static int ddb_port_attach(struct ddb_port *port) if (ret < 0) break; /* fallthrough */ - case DDB_PORT_LOOP: + case DDB_PORT_LOOP: ret = dvb_register_device(port->dvb[0].adap, &port->dvb[0].dev, &dvbdev_ci, (void *)port->output, @@ -2447,17 +2322,15 @@ static void input_tasklet(unsigned long data) dma->stat = ddbreadl(dev, DMA_BUFFER_CURRENT(dma)); dma->ctrl = ddbreadl(dev, DMA_BUFFER_CONTROL(dma)); -#if 1 { u32 packet_loss = dma->packet_loss; - u32 cur_counter = TS_STAT(input) & 0xFFFF; - - if ( cur_counter < (packet_loss & 0xFFFF) ) + u32 cur_counter = ddbreadl(dev, TS_STAT(input)) & 0xffff; + + if (cur_counter < (packet_loss & 0xffff)) packet_loss += 0x10000; - packet_loss = ((packet_loss & 0xFFFF0000) | cur_counter); + packet_loss = ((packet_loss & 0xffff0000) | cur_counter); dma->packet_loss = packet_loss; } -#endif if (4 & dma->ctrl) dma->stall_count++; if (input->redi) @@ -2468,7 +2341,7 @@ static void input_tasklet(unsigned long data) spin_unlock_irqrestore(&dma->lock, flags); } -#if 0 +#ifdef OPTIMIZE_TASKLETS static void input_handler(unsigned long data) { struct ddb_input *input = (struct ddb_input *)data; @@ -2530,7 +2403,7 @@ unlock_exit: spin_unlock_irqrestore(&dma->lock, flags); } -#if 0 +#ifdef OPTIMIZE_TASKLETS static void output_handler(void *data) { struct ddb_output *output = (struct ddb_output *)data; @@ -2620,10 +2493,6 @@ static void ddb_dma_init(struct ddb_io *io, int nr, int out, int irq_nr) dma->div = 1; } ddbwritel(io->port->dev, 0, DMA_BUFFER_ACK(dma)); -#if 0 - dev_info(io->port->dev->dev, "init link %u, io %u, dma %u, dmaregs %08x bufregs %08x\n", - io->port->lnr, io->nr, nr, dma->regs, dma->bufregs); -#endif } static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr) @@ -2648,10 +2517,6 @@ static void ddb_input_init(struct ddb_port *port, int nr, int pnr, int anr) if (port->lnr) dma_nr += 32 + (port->lnr - 1) * 8; -#if 0 - dev_info(dev->dev, "init link %u, input %u, handler %u\n", - port->lnr, nr, dma_nr + base); -#endif ddb_irq_set(dev, 0, dma_nr + base, &input_handler, input); ddb_dma_init(input, dma_nr, 0, dma_nr + base); } @@ -2669,10 +2534,6 @@ static void ddb_output_init(struct ddb_port *port, int nr) rm = io_regmap(output, 1); output->regs = DDB_LINK_TAG(port->lnr) | (rm->output->base + rm->output->size * nr); -#if 0 - dev_info(dev->dev, "init link %u, output %u, regs %08x\n", - port->lnr, nr, output->regs); -#endif if (dev->has_dma) { const struct ddb_regmap *rm0 = io_regmap(output, 0); u32 base = rm0->irq_base_odma; @@ -3683,7 +3544,7 @@ static ssize_t temp_show(struct device *device, l = attr->attr.name[5] - 0x30; link = &dev->link[l]; - if (link->info->type == DDB_MOD ) { + if (link->info->type == DDB_MOD) { if (link->info->version >= 2) { temp = 0xffff & ddbreadl(dev, TEMPMON2_BOARD); temp = (temp * 1000) >> 8; @@ -3755,25 +3616,6 @@ static ssize_t ctemp_show(struct device *device, return sprintf(buf, "%d\n", temp); } -#if 0 -static ssize_t qam_show(struct device *device, - struct device_attribute *attr, char *buf) -{ - struct ddb *dev = dev_get_drvdata(device); - struct i2c_adapter *adap; - u8 tmp[4]; - s16 i, q; - - adap = &dev->i2c[1].adap; - if (i2c_read_regs16(adap, 0x1f, 0xf480, tmp, 4) < 0) - return sprintf(buf, "read_error\n"); - i = (s16)(((u16)tmp[1]) << 14) | (((u16)tmp[0]) << 6); - q = (s16)(((u16)tmp[3]) << 14) | (((u16)tmp[2]) << 6); - - return sprintf(buf, "%d %d\n", i, q); -} -#endif - static ssize_t mod_show(struct device *device, struct device_attribute *attr, char *buf) { @@ -3954,32 +3796,6 @@ static ssize_t redirect_store(struct device *device, return count; } -#if 0 -/* A L P I AAAAAALLPPPPPPII */ -/* AAAAAAAA LLLLLLLL PPPPPPII */ -static ssize_t redirect2_show(struct device *device, - struct device_attribute *attr, char *buf) -{ - return 0; -} - -static ssize_t redirect2_store(struct device *device, - struct device_attribute *attr, - const char *buf, size_t count) -{ - unsigned int i, p; - int res; - - if (sscanf(buf, "%x %x\n", &i, &p) != 2) - return -EINVAL; - res = ddb_redirect(i, p); - if (res < 0) - return res; - dev_info(device, "redirect: %02x, %02x\n", i, p); - return count; -} -#endif - static ssize_t gap_show(struct device *device, struct device_attribute *attr, char *buf) { @@ -4137,9 +3953,6 @@ static struct device_attribute ddb_attrs[] = { __ATTR_MRO(devid3, devid_show), __ATTR_RO(hwid), __ATTR_RO(regmap), -#if 0 - __ATTR_RO(qam), -#endif __ATTR(redirect, 0664, redirect_show, redirect_store), __ATTR_MRO(snr, bsnr_show), __ATTR_RO(bpsnr), @@ -4239,7 +4052,6 @@ static void ddb_device_attrs_del(struct ddb *dev) if (dev->link[i].info && dev->link[i].info->temp_num) device_remove_file(dev->ddb_dev, &ddb_attrs_temp[i]); - for (i = 0; i < dev->link[0].info->temp_num; i++) for (i = 0; i < dev->link[0].info->port_num; i++) device_remove_file(dev->ddb_dev, &ddb_attrs_mod[i]); for (i = 0; i < dev->link[0].info->fan_num; i++) @@ -4377,7 +4189,9 @@ static void link_tasklet(unsigned long data) static void gtl_irq_handler(void *priv) { struct ddb_link *link = (struct ddb_link *)priv; -#if 1 +#ifdef USE_LINK_TASKLET + tasklet_schedule(&link->tasklet); +#else struct ddb *dev = link->dev; u32 s, l = link->nr, tag = DDB_LINK_TAG(link->nr); @@ -4389,8 +4203,6 @@ static void gtl_irq_handler(void *priv) LINK_IRQ_HANDLE(l, 3); LINK_IRQ_HANDLE(l, 24); } -#else - tasklet_schedule(&link->tasklet); #endif } @@ -4434,7 +4246,7 @@ static int ddb_gtl_init_link(struct ddb *dev, u32 l) subid & 0xffff, subid >> 16); if (link->info->type != DDB_OCTOPUS_MAX_CT && link->info->type != DDB_OCTOPUS_MAX && - link->info->type != DDB_OCTOPUS_MCI ) { + link->info->type != DDB_OCTOPUS_MCI) { dev_info(dev->dev, "Detected GT link but found invalid ID %08x. You might have to update (flash) the add-on card first.", id); diff --git a/ddbridge/ddbridge-hw.c b/ddbridge/ddbridge-hw.c index c778962..af34a1e 100644 --- a/ddbridge/ddbridge-hw.c +++ b/ddbridge/ddbridge-hw.c @@ -801,7 +801,7 @@ static const struct ddb_device_id ddb_device_ids[] = { DDB_DEVID(0x0013, 0x0044, ddb_ci_s2_pro_a), DDB_DEVID(0x0020, 0x0012, ddb_gtl_mini), - /* Modulators */ + /* Modulators */ DDB_DEVID(0x0201, 0x0001, ddb_mod), DDB_DEVID(0x0201, 0x0002, ddb_mod), DDB_DEVID(0x0201, 0x0004, ddb_mod_4), /* dummy entry ! */ @@ -827,10 +827,10 @@ const struct ddb_info *get_ddb_info(u16 vendor, u16 device, u16 subvendor, u16 subdevice) { int i; - + for (i = 0; i < ARRAY_SIZE(ddb_device_ids); i++) { const struct ddb_device_id *id = &ddb_device_ids[i]; - + if (vendor == id->vendor && device == id->device && subvendor == id->subvendor && diff --git a/ddbridge/ddbridge-i2c.c b/ddbridge/ddbridge-i2c.c index 20e8610..5a850ff 100644 --- a/ddbridge/ddbridge-i2c.c +++ b/ddbridge/ddbridge-i2c.c @@ -35,33 +35,30 @@ static int ddb_i2c_cmd(struct ddb_i2c *i2c, u32 adr, u32 cmd) stat = wait_for_completion_timeout(&i2c->completion, HZ); val = ddbreadl(dev, i2c->regs + I2C_COMMAND); if (stat == 0) { + u32 istat = ddbreadl(dev, INTERRUPT_STATUS); + dev_err(dev->dev, "I2C timeout, card %d, port %d, link %u\n", dev->nr, i2c->nr, i2c->link); -#if 1 - { - u32 istat = ddbreadl(dev, INTERRUPT_STATUS); + dev_err(dev->dev, "DDBridge IRS %08x\n", istat); - dev_err(dev->dev, "DDBridge IRS %08x\n", istat); - if (i2c->link) { - u32 listat = - ddbreadl(dev, - DDB_LINK_TAG(i2c->link) | - INTERRUPT_STATUS); - dev_err(dev->dev, - "DDBridge link %u IRS %08x\n", - i2c->link, listat); - } - if (istat & 1) { - ddbwritel(dev, istat & 1, INTERRUPT_ACK); - } else { - u32 mon = ddbreadl(dev, - i2c->regs + I2C_MONITOR); - - dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n", - val, mon); - } + if (i2c->link) { + u32 listat = + ddbreadl(dev, + DDB_LINK_TAG(i2c->link) | + INTERRUPT_STATUS); + dev_err(dev->dev, + "DDBridge link %u IRS %08x\n", + i2c->link, listat); + } + if (istat & 1) { + ddbwritel(dev, istat & 1, INTERRUPT_ACK); + } else { + u32 mon = ddbreadl(dev, + i2c->regs + I2C_MONITOR); + + dev_err(dev->dev, "I2C cmd=%08x mon=%08x\n", + val, mon); } -#endif return -EIO; } val &= 0x70000; diff --git a/ddbridge/ddbridge-i2c.h b/ddbridge/ddbridge-i2c.h index 135704f..d21911a 100644 --- a/ddbridge/ddbridge-i2c.h +++ b/ddbridge/ddbridge-i2c.h @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +/* SPDX-License-Identifier: GPL-2.0 */ /* * ddbridge-i2c.h: Digital Devices bridge i2c driver * diff --git a/ddbridge/ddbridge-io.c b/ddbridge/ddbridge-io.c index 4c696f3..8844a24 100644 --- a/ddbridge/ddbridge-io.c +++ b/ddbridge/ddbridge-io.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ddbridge-io.c: Digital Devices bridge I/O functions * diff --git a/ddbridge/ddbridge-io.h b/ddbridge/ddbridge-io.h index 7626ff8..283fef5 100644 --- a/ddbridge/ddbridge-io.h +++ b/ddbridge/ddbridge-io.h @@ -1,3 +1,4 @@ +/* SPDX-License-Identifier: GPL-2.0 */ /* * ddbridge-io.h: Digital Devices bridge I/O functions * @@ -64,7 +65,7 @@ static inline u32 ddblreadl0(struct ddb_link *link, u32 adr) return readl(link->dev->regs + adr); } -#if 0 +#ifdef DEBUG_GTLW static inline void gtlw(struct ddb_link *link) { u32 count = 0; diff --git a/ddbridge/ddbridge-m4.c b/ddbridge/ddbridge-m4.c index e0cd533..1b29312 100644 --- a/ddbridge/ddbridge-m4.c +++ b/ddbridge/ddbridge-m4.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ddbridge-m4.c: Digital Devices MAX M4 driver * @@ -335,6 +336,7 @@ static int set_parameters(struct dvb_frontend *fe) { struct m4 *state = fe->demodulator_priv; int res; + //struct dtv_frontend_properties *p = &fe->dtv_property_cache; stop(fe); @@ -343,6 +345,7 @@ static int set_parameters(struct dvb_frontend *fe) state->iq_constellation_point_max = 0; state->iq_constellation_tap = 0; + //printk("bw = %u\n", p->bandwidth_hz); switch (fe->dtv_property_cache.delivery_system) { case SYS_DVBS: case SYS_DVBS2: @@ -450,7 +453,7 @@ static void release(struct dvb_frontend *fe) kfree(state); } -static int get_algo(struct dvb_frontend *fe) +static enum dvbfe_algo get_algo(struct dvb_frontend *fe) { return DVBFE_ALGO_HW; } @@ -470,21 +473,21 @@ static struct dvb_frontend_ops m4_ops = { SYS_DVBS, SYS_DVBS2, SYS_ISDBS, }, .info = { .name = "M4", - .frequency_min = 950000, /* DVB-T: 47125000 */ - .frequency_max = 865000000, /* DVB-C: 862000000 */ + .frequency_min_hz = 47125000, /* DVB-T: 47125000 */ + .frequency_max_hz = 2150000000, /* DVB-C: 862000000 */ .symbol_rate_min = 100000, .symbol_rate_max = 100000000, - .frequency_stepsize = 0, - .frequency_tolerance = 0, + .frequency_stepsize_hz = 0, + .frequency_tolerance_hz = 0, .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | - FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | - FE_CAN_QAM_AUTO | - FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | - FE_CAN_FEC_4_5 | - FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | - FE_CAN_TRANSMISSION_MODE_AUTO | - FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | - FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION + FE_CAN_QAM_64 | FE_CAN_QAM_128 | FE_CAN_QAM_256 | + FE_CAN_QAM_AUTO | + FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | + FE_CAN_FEC_4_5 | + FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | + FE_CAN_TRANSMISSION_MODE_AUTO | + FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO | + FE_CAN_RECOVER | FE_CAN_MUTE_TS | FE_CAN_2G_MODULATION }, .release = release, .get_frontend_algo = get_algo, diff --git a/ddbridge/ddbridge-main.c b/ddbridge/ddbridge-main.c index 0ed622b..94da972 100644 --- a/ddbridge/ddbridge-main.c +++ b/ddbridge/ddbridge-main.c @@ -360,17 +360,17 @@ static int __devinit ddb_probe(struct pci_dev *pdev, if (dev->link[0].info->type == DDB_MOD && dev->link[0].info->version == 2) { u32 lic = ddbreadl(dev, 0x1c) & 7; - + switch (lic) { - case 0: + case 0: dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0000); break; - case 1: + case 1: dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0003); break; - case 3: + case 3: dev->link[0].info = get_ddb_info(0xdd01, 0x0210, 0xdd01, 0x0002); break; @@ -458,11 +458,9 @@ static pci_ers_result_t ddb_pci_error_detected(struct pci_dev *pdev, { switch (state) { case pci_channel_io_frozen: - return PCI_ERS_RESULT_CAN_RECOVER; case pci_channel_io_perm_failure: return PCI_ERS_RESULT_DISCONNECT; - break; case pci_channel_io_normal: default: break; diff --git a/ddbridge/ddbridge-max.c b/ddbridge/ddbridge-max.c index 9a58602..8816afe 100644 --- a/ddbridge/ddbridge-max.c +++ b/ddbridge/ddbridge-max.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ddbridge-max.c: Digital Devices MAX card line support functions * @@ -67,7 +68,7 @@ static int max_emulate_switch(struct dvb_frontend *fe, { int input; - if (len !=4) + if (len != 4) return -1; if ((cmd[0] != 0xe0) || (cmd[1] != 0x10) || (cmd[2] != 0x39)) @@ -490,9 +491,6 @@ int ddb_fe_attach_mxl5xx(struct ddb_input *input) /* MAX MCI related functions */ -extern struct mci_cfg ddb_max_sx8_cfg; -extern struct mci_cfg ddb_max_m4_cfg; - int ddb_fe_attach_mci(struct ddb_input *input, u32 type) { struct ddb *dev = input->port->dev; @@ -502,7 +500,7 @@ int ddb_fe_attach_mci(struct ddb_input *input, u32 type) int demod, tuner; struct mci_cfg cfg; int fm = fmode; - + demod = input->nr; tuner = demod & 3; switch (type) { diff --git a/ddbridge/ddbridge-mci.c b/ddbridge/ddbridge-mci.c index a5683a0..66ad2f5 100644 --- a/ddbridge/ddbridge-mci.c +++ b/ddbridge/ddbridge-mci.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0 /* * ddbridge-mci.c: Digital Devices microcode interface * @@ -38,7 +39,7 @@ static int mci_reset(struct mci *state) msleep(300); ddblwritel(link, 0, MCI_CONTROL); - while(1) { + while (1) { status = ddblreadl(link, MCI_CONTROL); if ((status & MCI_CONTROL_READY) == MCI_CONTROL_READY) break; @@ -46,7 +47,7 @@ static int mci_reset(struct mci *state) break; msleep(50); } - if ((status & MCI_CONTROL_READY) == 0 ) + if ((status & MCI_CONTROL_READY) == 0) return -1; if (link->ids.device == 0x0009 || link->ids.device == 0x000b) ddblwritel(link, SX8_TSCONFIG_MODE_NORMAL, SX8_TSCONFIG); @@ -71,7 +72,7 @@ static int ddb_mci_cmd_raw_unlocked(struct mci *state, struct ddb_link *link = state->base->link; u32 i, val; unsigned long stat; - + val = ddblreadl(link, MCI_CONTROL); if (val & (MCI_CONTROL_RESET | MCI_CONTROL_START_COMMAND)) return -EIO; @@ -80,19 +81,21 @@ static int ddb_mci_cmd_raw_unlocked(struct mci *state, ddblwritel(link, cmd[i], MCI_COMMAND + i * 4); val |= (MCI_CONTROL_START_COMMAND | MCI_CONTROL_ENABLE_DONE_INTERRUPT); ddblwritel(link, val, MCI_CONTROL); - + stat = wait_for_completion_timeout(&state->base->completion, HZ); if (stat == 0) { u32 istat = ddblreadl(link, INTERRUPT_STATUS); - printk("MCI timeout\n"); + dev_err(state->base->link->dev->dev, "MCI timeout\n"); val = ddblreadl(link, MCI_CONTROL); if (val == 0xffffffff) { - printk("Lost PCIe link!\n"); + dev_err(state->base->link->dev->dev, + "Lost PCIe link!\n"); return -EIO; } else { - printk("DDBridge IRS %08x link %u\n", istat, link->nr); - if (istat & 1) + dev_err(state->base->link->dev->dev, + "DDBridge IRS %08x link %u\n", istat, link->nr); + if (istat & 1) ddblwritel(link, istat, INTERRUPT_ACK); if (link->nr) ddbwritel(link->dev, 0xffffff, INTERRUPT_ACK); @@ -110,7 +113,7 @@ int ddb_mci_cmd_unlocked(struct mci *state, { u32 *cmd = (u32 *) command; u32 *res = (u32 *) result; - + return ddb_mci_cmd_raw_unlocked(state, cmd, sizeof(*command)/sizeof(u32), res, sizeof(*result)/sizeof(u32)); } @@ -141,7 +144,7 @@ int ddb_mci_cmd_raw(struct mci *state, struct mci_result *result, u32 result_len) { int stat; - + mutex_lock(&state->base->mci_lock); stat = ddb_mci_cmd_raw_unlocked(state, (u32 *)command, command_len, @@ -186,8 +189,7 @@ int ddb_mci_get_snr(struct dvb_frontend *fe) p->cnr.len = 1; p->cnr.stat[0].scale = FE_SCALE_DECIBEL; - p->cnr.stat[0].svalue = (s64) mci-> - signal_info.dvbs2_signal_info.signal_to_noise * 10; + p->cnr.stat[0].svalue = (s64) mci->signal_info.dvbs2_signal_info.signal_to_noise * 10; return 0; } @@ -249,7 +251,7 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) ROLLOFF_35, ROLLOFF_25, ROLLOFF_20, ROLLOFF_10, ROLLOFF_5, ROLLOFF_15, ROLLOFF_35, ROLLOFF_35 }; - + p->frequency = mci->signal_info.dvbs2_signal_info.frequency; switch (p->delivery_system) { @@ -259,7 +261,6 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) { u32 pls_code = mci->signal_info.dvbs2_signal_info.pls_code; - p->frequency = mci->signal_info.dvbs2_signal_info.frequency / 1000; p->delivery_system = @@ -267,11 +268,10 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) SYS_DVBS2 : SYS_DVBS; if (mci->signal_info.dvbs2_signal_info.standard == 2) { u32 modcod = (0x7c & pls_code) >> 2; - + p->delivery_system = SYS_DVBS2; p->rolloff = - ro_lut[mci->signal_info. - dvbs2_signal_info.roll_off & 7]; + ro_lut[mci->signal_info.dvbs2_signal_info.roll_off & 7]; p->pilot = (pls_code & 1) ? PILOT_ON : PILOT_OFF; p->fec_inner = modcod2fec[modcod]; p->modulation = modcod2mod[modcod]; @@ -314,8 +314,8 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) p->cnr.len = 1; p->cnr.stat[0].scale = FE_SCALE_DECIBEL; - p->cnr.stat[0].svalue = (s64) mci-> - signal_info.dvbs2_signal_info.signal_to_noise * 10; + p->cnr.stat[0].svalue = (s64) + mci->signal_info.dvbs2_signal_info.signal_to_noise * 10; p->strength.len = 1; p->strength.stat[0].scale = FE_SCALE_DECIBEL; diff --git a/ddbridge/ddbridge-mci.h b/ddbridge/ddbridge-mci.h index a1b2fa9..8ed3a58 100644 --- a/ddbridge/ddbridge-mci.h +++ b/ddbridge/ddbridge-mci.h @@ -644,14 +644,13 @@ struct mci_result { u8 min_input_stream_id; u8 max_input_stream_id; } BBHeader; - + struct { u8 Mode; // FFT Mode 1,2,3 - u8 GuardInterval; // 1/32, 1/16, 1/8, /14 - - u8 TMCCInfo[13]; // TMCC B20 - B121, byte 0 bit 7: B20, byte 12 bit 2: B121 + u8 GuardInterval; // 1/32, 1/16, 1/8, /14 + u8 TMCCInfo[13]; // TMCC B20 - B121, byte 0 bit 7: B20, byte 12 bit 2: B121 } ISDBT_TMCCInfo; - + struct { u8 Change; // 5 bits, increments with every change struct { @@ -710,7 +709,7 @@ struct mci_result { /* DVB-T2 L1-Post Signalling Data ( ETSI EN 302 755 V1.4.1 Chapter 7.2.3 ) */ -#define L1POST_SUB_SLICES_PER_FRAME(p) (((u16)(p)[ 0] & 0x7F) | (p)[ 1]) +#define L1POST_SUB_SLICES_PER_FRAME(p) (((u16)(p)[0] & 0x7F) | (p)[1]) #define L1POST_NUM_PLP(p) ((p)[2] & 0xFF) #define L1POST_NUM_AUX(p) ((p)[3] & 0x0F) #define L1POST_AUX_CONFIG_RFU(p) ((p)[4] & 0xFF) @@ -750,8 +749,6 @@ struct mci_base { void *key; struct ddb_link *link; struct completion completion; - struct i2c_adapter *i2c; - struct mutex i2c_lock; struct mutex tuner_lock; struct mutex mci_lock; int count; @@ -788,4 +785,7 @@ int ddb_mci_get_info(struct mci *mci); int ddb_mci_get_strength(struct dvb_frontend *fe); void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p); +extern struct mci_cfg ddb_max_sx8_cfg; +extern struct mci_cfg ddb_max_m4_cfg; + #endif diff --git a/ddbridge/ddbridge-ns.c b/ddbridge/ddbridge-ns.c index 16a0700..57c7cf7 100644 --- a/ddbridge/ddbridge-ns.c +++ b/ddbridge/ddbridge-ns.c @@ -441,11 +441,11 @@ static int ns_start(struct dvbnss *nss) reg |= 0x40; if (nss->params.flags & DVB_NS_IPV6) reg |= 0x80; + ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16), + STREAM_CONTROL(dns->nr)); if (dns->fe != input) ddb_dvb_ns_input_start(dns->fe); ddb_dvb_ns_input_start(input); - ddbwritel(dev, reg | (dns->fe->nr << 8) | (dns->fe->port->lnr << 16), - STREAM_CONTROL(dns->nr)); return 0; } diff --git a/ddbridge/ddbridge-sx8.c b/ddbridge/ddbridge-sx8.c index 9f4c017..d3bc223 100644 --- a/ddbridge/ddbridge-sx8.c +++ b/ddbridge/ddbridge-sx8.c @@ -501,7 +501,7 @@ static int tune(struct dvb_frontend *fe, bool re_tune, return 0; } -static int get_algo(struct dvb_frontend *fe) +static enum dvbfe_algo get_algo(struct dvb_frontend *fe) { return DVBFE_ALGO_HW; } @@ -541,10 +541,10 @@ static struct dvb_frontend_ops sx8_ops = { .xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */ .info = { .name = "DVB-S/S2X", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 0, - .frequency_tolerance = 0, + .frequency_min_hz = 950000000, + .frequency_max_hz = 2150000000, + .frequency_stepsize_hz = 0, + .frequency_tolerance_hz = 0, .symbol_rate_min = 100000, .symbol_rate_max = 100000000, .caps = FE_CAN_INVERSION_AUTO | diff --git a/ddbridge/ddbridge.h b/ddbridge/ddbridge.h index 51f47cd..4ee5252 100644 --- a/ddbridge/ddbridge.h +++ b/ddbridge/ddbridge.h @@ -60,22 +60,20 @@ #include #include #include -#include #include #include #include #include -#include #include "dvb_netstream.h" -#include "dmxdev.h" -#include "dvbdev.h" -#include "dvb_demux.h" -#include "dvb_frontend.h" -#include "dvb_ringbuffer.h" -#include "dvb_ca_en50221.h" -#include "dvb_net.h" +#include +#include +#include +#include +#include +#include +#include #include "tda18271c2dd.h" #include "stv6110x.h" @@ -238,7 +236,7 @@ struct ddb_dvb { enum fe_sec_tone_mode tone; enum fe_sec_voltage voltage; - int (*i2c_gate_ctrl)(struct dvb_frontend *, int); + int (*i2c_gate_ctrl)(struct dvb_frontend *fe, int val); int (*set_voltage)(struct dvb_frontend *fe, enum fe_sec_voltage voltage); int (*set_input)(struct dvb_frontend *fe, int input); @@ -408,7 +406,7 @@ struct ddb_lnb { }; struct ddb_irq { - void (*handler)(void *); + void (*handler)(void *data); void *data; }; @@ -542,7 +540,7 @@ int ddbridge_mod_do_ioctl(struct file *file, unsigned int cmd, void *parg); int ddbridge_mod_init(struct ddb *dev); void ddbridge_mod_output_stop(struct ddb_output *output); int ddbridge_mod_output_start(struct ddb_output *output); -void ddbridge_mod_rate_handler(void *); +void ddbridge_mod_rate_handler(void *data); void ddb_device_destroy(struct ddb *dev); void ddb_nsd_detach(struct ddb *dev); diff --git a/ddbridge/dvb_netstream.h b/ddbridge/dvb_netstream.h index a40f1f1..ca2a0a5 100644 --- a/ddbridge/dvb_netstream.h +++ b/ddbridge/dvb_netstream.h @@ -38,7 +38,7 @@ #include #include -#include "dvbdev.h" +#include #define DVBNS_MAXPIDS 32 diff --git a/dvb-core/Kconfig b/dvb-core/Kconfig index e7b2bdd..6ffac61 100644 --- a/dvb-core/Kconfig +++ b/dvb-core/Kconfig @@ -3,6 +3,32 @@ # DVB device configuration # +config DVB_MMAP + bool "Enable DVB memory-mapped API (EXPERIMENTAL)" + depends on DVB_CORE + depends on VIDEO_V4L2=y || VIDEO_V4L2=DVB_CORE + select VIDEOBUF2_VMALLOC + help + This option enables DVB experimental memory-mapped API, which + reduces the number of context switches to read DVB buffers, as + the buffers can use mmap() syscalls. + + Support for it is experimental. Use with care. If unsure, + say N. + +config DVB_NET + bool "DVB Network Support" + default (NET && INET) + depends on NET && INET && DVB_CORE + help + This option enables DVB Network Support which is a part of the DVB + standard. It is used, for example, by automatic firmware updates used + on Set-Top-Boxes. It can also be used to access the Internet via the + DVB card, if the network provider supports it. + + You may want to disable the network support on embedded devices. If + unsure say Y. + config DVB_MAX_ADAPTERS int "maximum number of DVB/ATSC adapters" depends on DVB_CORE @@ -19,7 +45,7 @@ config DVB_MAX_ADAPTERS config DVB_DYNAMIC_MINORS bool "Dynamic DVB minor allocation" depends on DVB_CORE - default n + default y help If you say Y here, the DVB subsystem will use dynamic minor allocation for any device that uses the DVB major number. @@ -32,7 +58,6 @@ config DVB_DYNAMIC_MINORS config DVB_DEMUX_SECTION_LOSS_LOG bool "Enable DVB demux section packet loss log" depends on DVB_CORE - default n help Enable extra log messages meant to detect packet loss inside the Kernel. @@ -41,3 +66,15 @@ config DVB_DEMUX_SECTION_LOSS_LOG be very verbose. If you are unsure about this, say N here. + +config DVB_ULE_DEBUG + bool "Enable DVB net ULE packet debug messages" + depends on DVB_CORE + help + Enable extra log messages meant to detect problems while + handling DVB network ULE packet loss inside the Kernel. + + Should not be enabled on normal cases, as logs can + be very verbose. + + If you are unsure about this, say N here. diff --git a/dvb-core/Makefile b/dvb-core/Makefile index c8a5f48..28e3437 100644 --- a/dvb-core/Makefile +++ b/dvb-core/Makefile @@ -3,11 +3,14 @@ # Makefile for the kernel DVB device drivers. # -dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ +dvb-net-$(CONFIG_DVB_NET) := dvb_net.o +dvb-vb2-$(CONFIG_DVB_MMAP) := dvb_vb2.o + +dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o \ dvb_ca_en50221.o dvb_frontend.o \ - dvb_net.o dvb_ringbuffer.o dvb_math.o + $(dvb-net-y) dvb_ringbuffer.o $(dvb-vb2-y) dvb_math.o obj-$(CONFIG_DVB_CORE) += dvb-core.o EXTRA_CFLAGS += -DCONFIG_DVB_DYNAMIC_MINORS -DCONFIG_DVB_NET -NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core +#NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/include/linux diff --git a/dvb-core/Makefile.kernel b/dvb-core/Makefile.kernel index 8f22bcd..51d161a 100644 --- a/dvb-core/Makefile.kernel +++ b/dvb-core/Makefile.kernel @@ -9,3 +9,5 @@ dvb-core-objs := dvbdev.o dmxdev.o dvb_demux.o dvb_filter.o \ $(dvb-net-y) dvb_ringbuffer.o dvb_math.o obj-$(CONFIG_DVB_CORE) += dvb-core.o + +ccflags-y += -Idrivers/media/dvb-core/ diff --git a/dvb-core/dmxdev.c b/dvb-core/dmxdev.c index eade5a7..6d09853 100644 --- a/dvb-core/dmxdev.c +++ b/dvb-core/dmxdev.c @@ -18,6 +18,7 @@ #define pr_fmt(fmt) "dmxdev: " fmt +#include #include #include #include @@ -27,8 +28,10 @@ #include #include #include -#include -#include "dmxdev.h" +#include +#ifdef CONFIG_DVB_MMAP +#include +#endif static int debug; @@ -128,6 +131,7 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; struct dmx_frontend *front; + bool need_ringbuffer = false; dprintk("%s\n", __func__); @@ -139,14 +143,33 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) return -ENODEV; } - if ((file->f_flags & O_ACCMODE) == O_RDWR) { + dmxdev->may_do_mmap = 0; + + /* + * The logic here is a little tricky due to the ifdef. + * + * The ringbuffer is used for both read and mmap. + * + * It is not needed, however, on two situations: + * - Write devices (access with O_WRONLY); + * - For duplex device nodes, opened with O_RDWR. + */ + + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + need_ringbuffer = true; + else if ((file->f_flags & O_ACCMODE) == O_RDWR) { if (!(dmxdev->capabilities & DMXDEV_CAP_DUPLEX)) { +#ifdef CONFIG_DVB_MMAP + dmxdev->may_do_mmap = 1; + need_ringbuffer = true; +#else mutex_unlock(&dmxdev->mutex); return -EOPNOTSUPP; +#endif } } - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (need_ringbuffer) { void *mem; if (!dvbdev->readers) { @@ -159,6 +182,11 @@ static int dvb_dvr_open(struct inode *inode, struct file *file) return -ENOMEM; } dvb_ringbuffer_init(&dmxdev->dvr_buffer, mem, DVR_BUFFER_SIZE); +#ifdef CONFIG_DVB_MMAP + if (dmxdev->may_do_mmap) + dvb_vb2_init(&dmxdev->dvr_vb2_ctx, "dvr", + file->f_flags & O_NONBLOCK); +#endif dvbdev->readers--; } @@ -196,7 +224,15 @@ static int dvb_dvr_release(struct inode *inode, struct file *file) dmxdev->demux->connect_frontend(dmxdev->demux, dmxdev->dvr_orig_fe); } - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (((file->f_flags & O_ACCMODE) == O_RDONLY) || + dmxdev->may_do_mmap) { +#ifdef CONFIG_DVB_MMAP + if (dmxdev->may_do_mmap) { + if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) + dvb_vb2_stream_off(&dmxdev->dvr_vb2_ctx); + dvb_vb2_release(&dmxdev->dvr_vb2_ctx); + } +#endif dvbdev->readers++; if (dmxdev->dvr_buffer.data) { void *mem = dmxdev->dvr_buffer.data; @@ -381,12 +417,18 @@ static void dvb_dmxdev_filter_timer(struct dmxdev_filter *dmxdevfilter) #endif static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, - struct dmx_section_filter *filter) + struct dmx_section_filter *filter, + u32 *buffer_flags) { struct dmxdev_filter *dmxdevfilter = filter->priv; int ret; +#ifdef CONFIG_DVB_MMAP + if (!dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx) && + dmxdevfilter->buffer.error) { +#else if (dmxdevfilter->buffer.error) { +#endif wake_up(&dmxdevfilter->buffer.queue); return 0; } @@ -397,12 +439,31 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, } del_timer(&dmxdevfilter->timer); dprintk("section callback %*ph\n", 6, buffer1); +#ifdef CONFIG_DVB_MMAP + if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) { + ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, + buffer1, buffer1_len, + buffer_flags); + if (ret == buffer1_len) + ret = dvb_vb2_fill_buffer(&dmxdevfilter->vb2_ctx, + buffer2, buffer2_len, + buffer_flags); + } else { + ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, + buffer1, buffer1_len); + if (ret == buffer1_len) { + ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, + buffer2, buffer2_len); + } + } +#else ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer1, buffer1_len); if (ret == buffer1_len) { ret = dvb_dmxdev_buffer_write(&dmxdevfilter->buffer, buffer2, buffer2_len); } +#endif if (ret < 0) dmxdevfilter->buffer.error = ret; if (dmxdevfilter->params.sec.flags & DMX_ONESHOT) @@ -414,7 +475,8 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len, static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, - struct dmx_ts_feed *feed) + struct dmx_ts_feed *feed, + u32 *buffer_flags) { struct dmxdev_filter *dmxdevfilter = feed->priv; struct dvb_ringbuffer *buffer; @@ -426,19 +488,40 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len, return 0; } - if (dmxdevfilter->params.pes.output == DMX_OUT_TAP - || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) + if (dmxdevfilter->params.pes.output == DMX_OUT_TAP || + dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP) { buffer = &dmxdevfilter->buffer; - else +#ifdef CONFIG_DVB_MMAP + ctx = &dmxdevfilter->vb2_ctx; +#endif + } else { buffer = &dmxdevfilter->dev->dvr_buffer; - if (buffer->error) { - spin_unlock(&dmxdevfilter->dev->lock); - wake_up(&buffer->queue); - return 0; +#ifdef CONFIG_DVB_MMAP + ctx = &dmxdevfilter->dev->dvr_vb2_ctx; +#endif } - ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); - if (ret == buffer1_len) - ret = dvb_dmxdev_buffer_write(buffer, buffer2, buffer2_len); + +#ifdef CONFIG_DVB_MMAP + if (dvb_vb2_is_streaming(ctx)) { + ret = dvb_vb2_fill_buffer(ctx, buffer1, buffer1_len, + buffer_flags); + if (ret == buffer1_len) + ret = dvb_vb2_fill_buffer(ctx, buffer2, buffer2_len, + buffer_flags); + } else { +#endif + if (buffer->error) { + spin_unlock(&dmxdevfilter->dev->lock); + wake_up(&buffer->queue); + return 0; + } + ret = dvb_dmxdev_buffer_write(buffer, buffer1, buffer1_len); + if (ret == buffer1_len) + ret = dvb_dmxdev_buffer_write(buffer, + buffer2, buffer2_len); +#ifdef CONFIG_DVB_MMAP + } +#endif if (ret < 0) buffer->error = ret; spin_unlock(&dmxdevfilter->dev->lock); @@ -585,7 +668,7 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, struct dmxdev_filter *filter, struct dmxdev_feed *feed) { - ktime_t timeout; + ktime_t timeout = ktime_set(0, 0); struct dmx_pes_filter_params *para = &filter->params.pes; enum dmx_output otype; int ret; @@ -593,7 +676,6 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev, enum dmx_ts_pes ts_pes; struct dmx_ts_feed *tsfeed; - timeout = ktime_set(0, 0); feed->ts = NULL; otype = para->output; @@ -777,7 +859,17 @@ static int dvb_demux_open(struct inode *inode, struct file *file) mutex_init(&dmxdevfilter->mutex); file->private_data = dmxdevfilter; +#ifdef CONFIG_DVB_MMAP + dmxdev->may_do_mmap = 1; +#else + dmxdev->may_do_mmap = 0; +#endif + dvb_ringbuffer_init(&dmxdevfilter->buffer, NULL, 8192); +#ifdef CONFIG_DVB_MMAP + dvb_vb2_init(&dmxdevfilter->vb2_ctx, "demux_filter", + file->f_flags & O_NONBLOCK); +#endif dmxdevfilter->type = DMXDEV_TYPE_NONE; dvb_dmxdev_filter_state_set(dmxdevfilter, DMXDEV_STATE_ALLOCATED); #if (LINUX_VERSION_CODE >= KERNEL_VERSION(4, 15, 0)) @@ -797,6 +889,11 @@ static int dvb_dmxdev_filter_free(struct dmxdev *dmxdev, { mutex_lock(&dmxdev->mutex); mutex_lock(&dmxdevfilter->mutex); +#ifdef CONFIG_DVB_MMAP + if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) + dvb_vb2_stream_off(&dmxdevfilter->vb2_ctx); + dvb_vb2_release(&dmxdevfilter->vb2_ctx); +#endif dvb_dmxdev_filter_stop(dmxdevfilter); dvb_dmxdev_filter_reset(dmxdevfilter); @@ -1084,8 +1181,56 @@ static int dvb_demux_do_ioctl(struct file *file, mutex_unlock(&dmxdevfilter->mutex); break; +#ifdef CONFIG_DVB_MMAP + case DMX_REQBUFS: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_reqbufs(&dmxdevfilter->vb2_ctx, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_QUERYBUF: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_querybuf(&dmxdevfilter->vb2_ctx, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_EXPBUF: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_expbuf(&dmxdevfilter->vb2_ctx, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_QBUF: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_qbuf(&dmxdevfilter->vb2_ctx, parg); + if (ret == 0 && !dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) + ret = dvb_vb2_stream_on(&dmxdevfilter->vb2_ctx); + mutex_unlock(&dmxdevfilter->mutex); + break; + + case DMX_DQBUF: + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_dqbuf(&dmxdevfilter->vb2_ctx, parg); + mutex_unlock(&dmxdevfilter->mutex); + break; +#endif default: - ret = -EINVAL; + ret = -ENOTTY; break; } mutex_unlock(&dmxdev->mutex); @@ -1098,30 +1243,70 @@ static long dvb_demux_ioctl(struct file *file, unsigned int cmd, return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl); } -static unsigned int dvb_demux_poll(struct file *file, poll_table *wait) +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)) +typedef unsigned int __poll_t; +#define EPOLLIN POLLIN +#define EPOLLERR POLLERR +#define EPOLLPRI POLLPRI +#define EPOLLRDNORM POLLRDNORM +#define EPOLLWRNORM POLLWRNORM +#define EPOLLOUT POLLOUT +#endif + +static __poll_t dvb_demux_poll(struct file *file, poll_table *wait) { struct dmxdev_filter *dmxdevfilter = file->private_data; - unsigned int mask = 0; - - if ((!dmxdevfilter) || dmxdevfilter->dev->exit) - return POLLERR; + __poll_t mask = 0; poll_wait(file, &dmxdevfilter->buffer.queue, wait); + if ((!dmxdevfilter) || dmxdevfilter->dev->exit) + return EPOLLERR; +#ifdef CONFIG_DVB_MMAP + if (dvb_vb2_is_streaming(&dmxdevfilter->vb2_ctx)) + return dvb_vb2_poll(&dmxdevfilter->vb2_ctx, file, wait); +#endif + if (dmxdevfilter->state != DMXDEV_STATE_GO && dmxdevfilter->state != DMXDEV_STATE_DONE && dmxdevfilter->state != DMXDEV_STATE_TIMEDOUT) return 0; if (dmxdevfilter->buffer.error) - mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); + mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR); if (!dvb_ringbuffer_empty(&dmxdevfilter->buffer)) - mask |= (POLLIN | POLLRDNORM | POLLPRI); + mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI); return mask; } +#ifdef CONFIG_DVB_MMAP +static int dvb_demux_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct dmxdev_filter *dmxdevfilter = file->private_data; + struct dmxdev *dmxdev = dmxdevfilter->dev; + int ret; + + if (!dmxdev->may_do_mmap) + return -ENOTTY; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + if (mutex_lock_interruptible(&dmxdevfilter->mutex)) { + mutex_unlock(&dmxdev->mutex); + return -ERESTARTSYS; + } + ret = dvb_vb2_mmap(&dmxdevfilter->vb2_ctx, vma); + + mutex_unlock(&dmxdevfilter->mutex); + mutex_unlock(&dmxdev->mutex); + + return ret; +} +#endif + static int dvb_demux_release(struct inode *inode, struct file *file) { struct dmxdev_filter *dmxdevfilter = file->private_data; @@ -1146,10 +1331,14 @@ static const struct file_operations dvb_demux_fops = { .owner = THIS_MODULE, .read = dvb_demux_read, .unlocked_ioctl = dvb_demux_ioctl, + .compat_ioctl = dvb_demux_ioctl, .open = dvb_demux_open, .release = dvb_demux_release, .poll = dvb_demux_poll, .llseek = default_llseek, +#ifdef CONFIG_DVB_MMAP + .mmap = dvb_demux_mmap, +#endif }; static const struct dvb_device dvbdev_demux = { @@ -1178,8 +1367,31 @@ static int dvb_dvr_do_ioctl(struct file *file, ret = dvb_dvr_set_buffer_size(dmxdev, arg); break; +#ifdef CONFIG_DVB_MMAP + case DMX_REQBUFS: + ret = dvb_vb2_reqbufs(&dmxdev->dvr_vb2_ctx, parg); + break; + + case DMX_QUERYBUF: + ret = dvb_vb2_querybuf(&dmxdev->dvr_vb2_ctx, parg); + break; + + case DMX_EXPBUF: + ret = dvb_vb2_expbuf(&dmxdev->dvr_vb2_ctx, parg); + break; + + case DMX_QBUF: + ret = dvb_vb2_qbuf(&dmxdev->dvr_vb2_ctx, parg); + if (ret == 0 && !dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) + ret = dvb_vb2_stream_on(&dmxdev->dvr_vb2_ctx); + break; + + case DMX_DQBUF: + ret = dvb_vb2_dqbuf(&dmxdev->dvr_vb2_ctx, parg); + break; +#endif default: - ret = -EINVAL; + ret = -ENOTTY; break; } mutex_unlock(&dmxdev->mutex); @@ -1192,31 +1404,58 @@ static long dvb_dvr_ioctl(struct file *file, return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl); } -static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait) +static __poll_t dvb_dvr_poll(struct file *file, poll_table *wait) { struct dvb_device *dvbdev = file->private_data; struct dmxdev *dmxdev = dvbdev->priv; - unsigned int mask = 0; + __poll_t mask = 0; dprintk("%s\n", __func__); - if (dmxdev->exit) - return POLLERR; - poll_wait(file, &dmxdev->dvr_buffer.queue, wait); - if ((file->f_flags & O_ACCMODE) == O_RDONLY) { + if (dmxdev->exit) + return EPOLLERR; +#ifdef CONFIG_DVB_MMAP + if (dvb_vb2_is_streaming(&dmxdev->dvr_vb2_ctx)) + return dvb_vb2_poll(&dmxdev->dvr_vb2_ctx, file, wait); +#endif + + if (((file->f_flags & O_ACCMODE) == O_RDONLY) || + dmxdev->may_do_mmap) { if (dmxdev->dvr_buffer.error) - mask |= (POLLIN | POLLRDNORM | POLLPRI | POLLERR); + mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI | EPOLLERR); if (!dvb_ringbuffer_empty(&dmxdev->dvr_buffer)) - mask |= (POLLIN | POLLRDNORM | POLLPRI); + mask |= (EPOLLIN | EPOLLRDNORM | EPOLLPRI); } else - mask |= (POLLOUT | POLLWRNORM | POLLPRI); + mask |= (EPOLLOUT | EPOLLWRNORM | EPOLLPRI); return mask; } +#ifdef CONFIG_DVB_MMAP +static int dvb_dvr_mmap(struct file *file, struct vm_area_struct *vma) +{ + struct dvb_device *dvbdev = file->private_data; + struct dmxdev *dmxdev = dvbdev->priv; + int ret; + + if (!dmxdev->may_do_mmap) + return -ENOTTY; + + if (dmxdev->exit) + return -ENODEV; + + if (mutex_lock_interruptible(&dmxdev->mutex)) + return -ERESTARTSYS; + + ret = dvb_vb2_mmap(&dmxdev->dvr_vb2_ctx, vma); + mutex_unlock(&dmxdev->mutex); + return ret; +} +#endif + static const struct file_operations dvb_dvr_fops = { .owner = THIS_MODULE, .read = dvb_dvr_read, @@ -1226,6 +1465,9 @@ static const struct file_operations dvb_dvr_fops = { .release = dvb_dvr_release, .poll = dvb_dvr_poll, .llseek = default_llseek, +#ifdef CONFIG_DVB_MMAP + .mmap = dvb_dvr_mmap, +#endif }; static const struct dvb_device dvbdev_dvr = { @@ -1237,6 +1479,7 @@ static const struct dvb_device dvbdev_dvr = { #endif .fops = &dvb_dvr_fops }; + int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) { int i; @@ -1244,7 +1487,12 @@ int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *dvb_adapter) if (dmxdev->demux->open(dmxdev->demux) < 0) return -EUSERS; - dmxdev->filter = vmalloc(dmxdev->filternum * sizeof(struct dmxdev_filter)); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0)) + dmxdev->filter = vmalloc(sizeof(struct dmxdev_filter) * dmxdev->filternum); +#else + dmxdev->filter = vmalloc(array_size(sizeof(struct dmxdev_filter), + dmxdev->filternum)); +#endif if (!dmxdev->filter) return -ENOMEM; diff --git a/dvb-core/dmxdev.h b/dvb-core/dmxdev.h deleted file mode 100644 index 054fd4e..0000000 --- a/dvb-core/dmxdev.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - * dmxdev.h - * - * Copyright (C) 2000 Ralph Metzler & Marcus Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DMXDEV_H_ -#define _DMXDEV_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#include "dvbdev.h" -#include "demux.h" -#include "dvb_ringbuffer.h" - -enum dmxdev_type { - DMXDEV_TYPE_NONE, - DMXDEV_TYPE_SEC, - DMXDEV_TYPE_PES, -}; - -enum dmxdev_state { - DMXDEV_STATE_FREE, - DMXDEV_STATE_ALLOCATED, - DMXDEV_STATE_SET, - DMXDEV_STATE_GO, - DMXDEV_STATE_DONE, - DMXDEV_STATE_TIMEDOUT -}; - -struct dmxdev_feed { - u16 pid; - struct dmx_ts_feed *ts; - struct list_head next; -}; - -struct dmxdev_filter { - union { - struct dmx_section_filter *sec; - } filter; - - union { - /* list of TS and PES feeds (struct dmxdev_feed) */ - struct list_head ts; - struct dmx_section_feed *sec; - } feed; - - union { - struct dmx_sct_filter_params sec; - struct dmx_pes_filter_params pes; - } params; - - enum dmxdev_type type; - enum dmxdev_state state; - struct dmxdev *dev; - struct dvb_ringbuffer buffer; - - struct mutex mutex; - - /* only for sections */ - struct timer_list timer; - int todo; - u8 secheader[3]; -}; - - -struct dmxdev { - struct dvb_device *dvbdev; - struct dvb_device *dvr_dvbdev; - - struct dmxdev_filter *filter; - struct dmx_demux *demux; - - int filternum; - int capabilities; - - unsigned int exit:1; -#define DMXDEV_CAP_DUPLEX 1 - struct dmx_frontend *dvr_orig_fe; - - struct dvb_ringbuffer dvr_buffer; -#define DVR_BUFFER_SIZE (10*188*1024) - - struct mutex mutex; - spinlock_t lock; -}; - - -int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *); -void dvb_dmxdev_release(struct dmxdev *dmxdev); - -#endif /* _DMXDEV_H_ */ diff --git a/dvb-core/dvb_ca_en50221.c b/dvb-core/dvb_ca_en50221.c index 87db54f..c398c39 100644 --- a/dvb-core/dvb_ca_en50221.c +++ b/dvb-core/dvb_ca_en50221.c @@ -34,8 +34,8 @@ #endif #include -#include "dvb_ca_en50221.h" -#include "dvb_ringbuffer.h" +#include +#include static int dvb_ca_en50221_debug; diff --git a/dvb-core/dvb_demux.c b/dvb-core/dvb_demux.c index 5083a54..44c5fd2 100644 --- a/dvb-core/dvb_demux.c +++ b/dvb-core/dvb_demux.c @@ -35,7 +35,7 @@ #include #include -#include "dvb_demux.h" +#include #if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 0, 0)) @@ -68,6 +68,17 @@ MODULE_PARM_DESC(dvb_demux_feed_err_pkts, dprintk(x); \ } while (0) +#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG +# define dprintk_sect_loss(x...) dprintk(x) +#else +# define dprintk_sect_loss(x...) +#endif + +#define set_buf_flags(__feed, __flag) \ + do { \ + (__feed)->buffer_flags |= (__flag); \ + } while (0) + /****************************************************************************** * static inlined helper functions ******************************************************************************/ @@ -117,30 +128,30 @@ static inline int dvb_dmx_swfilter_payload(struct dvb_demux_feed *feed, { int count = payload(buf); int p; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG int ccok; u8 cc; -#endif if (count == 0) return -1; p = 188 - count; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG cc = buf[3] & 0x0f; ccok = ((feed->cc + 1) & 0x0f) == cc; feed->cc = cc; - if (!ccok) - dprintk("missed packet!\n"); -#endif + if (!ccok) { + set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("missed packet: %d instead of %d!\n", + cc, (feed->cc + 1) & 0x0f); + } if (buf[1] & 0x40) // PUSI ? feed->peslen = 0xfffa; feed->peslen += count; - return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts); + return feed->cb.ts(&buf[p], count, NULL, 0, &feed->feed.ts, + &feed->buffer_flags); } static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, @@ -162,7 +173,7 @@ static int dvb_dmx_swfilter_sectionfilter(struct dvb_demux_feed *feed, return 0; return feed->cb.sec(feed->feed.sec.secbuf, feed->feed.sec.seclen, - NULL, 0, &f->filter); + NULL, 0, &f->filter, &feed->buffer_flags); } static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) @@ -181,8 +192,10 @@ static inline int dvb_dmx_swfilter_section_feed(struct dvb_demux_feed *feed) if (sec->check_crc) { section_syntax_indicator = ((sec->secbuf[1] & 0x80) != 0); if (section_syntax_indicator && - demux->check_crc32(feed, sec->secbuf, sec->seclen)) + demux->check_crc32(feed, sec->secbuf, sec->seclen)) { + set_buf_flags(feed, DMX_BUFFER_FLAG_HAD_CRC32_DISCARD); return -1; + } } do { @@ -199,9 +212,8 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) { struct dmx_section_feed *sec = &feed->feed.sec; -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG if (sec->secbufp < sec->tsfeedp) { - int i, n = sec->tsfeedp - sec->secbufp; + int n = sec->tsfeedp - sec->secbufp; /* * Section padding is done with 0xff bytes entirely. @@ -209,15 +221,13 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) * but just first and last. */ if (sec->secbuf[0] != 0xff || sec->secbuf[n - 1] != 0xff) { - dprintk("dvb_demux.c section ts padding loss: %d/%d\n", - n, sec->tsfeedp); - dprintk("dvb_demux.c pad data:"); - for (i = 0; i < n; i++) - pr_cont(" %02x", sec->secbuf[i]); - pr_cont("\n"); + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("section ts padding loss: %d/%d\n", + n, sec->tsfeedp); + dprintk_sect_loss("pad data: %*ph\n", n, sec->secbuf); } } -#endif sec->tsfeedp = sec->secbufp = sec->seclen = 0; sec->secbuf = sec->secbuf_base; @@ -236,10 +246,10 @@ static void dvb_dmx_swfilter_section_new(struct dvb_demux_feed *feed) * when the second packet arrives. * * Fix: - * when demux is started, let feed->pusi_seen = 0 to + * when demux is started, let feed->pusi_seen = false to * prevent initial feeding of garbage from the end of * previous section. When you for the first time see PUSI=1 - * then set feed->pusi_seen = 1 + * then set feed->pusi_seen = true */ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, const u8 *buf, u8 len) @@ -252,11 +262,10 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, return 0; if (sec->tsfeedp + len > DMX_MAX_SECFEED_SIZE) { -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - dprintk("dvb_demux.c section buffer full loss: %d/%d\n", - sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, - DMX_MAX_SECFEED_SIZE); -#endif + set_buf_flags(feed, DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("section buffer full loss: %d/%d\n", + sec->tsfeedp + len - DMX_MAX_SECFEED_SIZE, + DMX_MAX_SECFEED_SIZE); len = DMX_MAX_SECFEED_SIZE - sec->tsfeedp; } @@ -284,12 +293,13 @@ static int dvb_dmx_swfilter_section_copy_dump(struct dvb_demux_feed *feed, sec->seclen = seclen; sec->crc_val = ~0; /* dump [secbuf .. secbuf+seclen) */ - if (feed->pusi_seen) + if (feed->pusi_seen) { dvb_dmx_swfilter_section_feed(feed); -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - else - dprintk("dvb_demux.c pusi not seen, discarding section data\n"); -#endif + } else { + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("pusi not seen, discarding section data\n"); + } sec->secbufp += seclen; /* secbufp and secbuf moving together is */ sec->secbuf += seclen; /* redundant but saves pointer arithmetic */ } @@ -322,19 +332,31 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, } if (!ccok || dc_i) { -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - dprintk("dvb_demux.c discontinuity detected %d bytes lost\n", - count); + if (dc_i) { + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_INDICATOR); + dprintk_sect_loss("%d frame with disconnect indicator\n", + cc); + } else { + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("discontinuity: %d instead of %d. %d bytes lost\n", + cc, (feed->cc + 1) & 0x0f, count + 4); + } /* - * those bytes under sume circumstances will again be reported + * those bytes under some circumstances will again be reported * in the following dvb_dmx_swfilter_section_new */ -#endif + /* - * Discontinuity detected. Reset pusi_seen = 0 to + * Discontinuity detected. Reset pusi_seen to * stop feeding of suspicious data until next PUSI=1 arrives + * + * FIXME: does it make sense if the MPEG-TS is the one + * reporting discontinuity? */ - feed->pusi_seen = 0; + + feed->pusi_seen = false; dvb_dmx_swfilter_section_new(feed); } @@ -348,17 +370,16 @@ static int dvb_dmx_swfilter_section_packet(struct dvb_demux_feed *feed, dvb_dmx_swfilter_section_copy_dump(feed, before, before_len); - /* before start of new section, set pusi_seen = 1 */ - feed->pusi_seen = 1; + /* before start of new section, set pusi_seen */ + feed->pusi_seen = true; dvb_dmx_swfilter_section_new(feed); dvb_dmx_swfilter_section_copy_dump(feed, after, after_len); + } else if (count > 0) { + set_buf_flags(feed, + DMX_BUFFER_FLAG_DISCONTINUITY_DETECTED); + dprintk_sect_loss("PUSI=1 but %d bytes lost\n", count); } -#ifdef CONFIG_DVB_DEMUX_SECTION_LOSS_LOG - else if (count > 0) - dprintk("dvb_demux.c PUSI=1 but %d bytes lost\n", - count); -#endif } else { /* PUSI=0 (is not set), no section boundary */ dvb_dmx_swfilter_section_copy_dump(feed, &buf[p], count); @@ -378,8 +399,10 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed, if (feed->ts_type & TS_PAYLOAD_ONLY) dvb_dmx_swfilter_payload(feed, buf); else - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, + &feed->buffer_flags); } + /* Used only on full-featured devices */ if (feed->ts_type & TS_DECODER) if (feed->demux->write_to_decoder) feed->demux->write_to_decoder(feed, buf, 188); @@ -426,9 +449,10 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) 1024); speed_timedelta = ktime_ms_delta(cur_time, demux->speed_last_time); - dprintk("TS speed %llu Kbits/sec \n", - div64_u64(speed_bytes, - speed_timedelta)); + if (speed_timedelta) + dprintk("TS speed %llu Kbits/sec \n", + div64_u64(speed_bytes, + speed_timedelta)); } demux->speed_last_time = cur_time; @@ -437,6 +461,11 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) } if (buf[1] & 0x80) { + list_for_each_entry(feed, &demux->feed_list, list_head) { + if ((feed->pid != pid) && (feed->pid != 0x2000)) + continue; + set_buf_flags(feed, DMX_BUFFER_FLAG_TEI); + } dprintk_tscheck("TEI detected. PID=0x%x data1=0x%x\n", pid, buf[1]); /* data in this packet can't be trusted - drop it unless @@ -452,6 +481,13 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) (demux->cnt_storage[pid] + 1) & 0xf; if ((buf[3] & 0xf) != demux->cnt_storage[pid]) { + list_for_each_entry(feed, &demux->feed_list, list_head) { + if ((feed->pid != pid) && (feed->pid != 0x2000)) + continue; + set_buf_flags(feed, + DMX_BUFFER_PKT_COUNTER_MISMATCH); + } + dprintk_tscheck("TS packet counter mismatch. PID=0x%x expected 0x%x got 0x%x\n", pid, demux->cnt_storage[pid], buf[3] & 0xf); @@ -473,7 +509,8 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf) if (feed->pid == pid) dvb_dmx_swfilter_packet_type(feed, buf); else if (feed->pid == 0x2000) - feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts); + feed->cb.ts(buf, 188, NULL, 0, &feed->feed.ts, + &feed->buffer_flags); } } @@ -592,7 +629,16 @@ void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, size_t count) spin_lock_irqsave(&demux->lock, flags); - demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts); +#if 1 + demux->feed->cb.ts(buf, count, NULL, 0, &demux->feed->feed.ts, + &demux->feed->buffer_flags); +#else + struct dvb_demux_feed *feed; + list_for_each_entry(feed, &demux->feed_list, list_head) { + feed->cb.ts(buf, count, NULL, 0, &feed->feed.ts, + &feed->buffer_flags); + } +#endif spin_unlock_irqrestore(&demux->lock, flags); } @@ -792,6 +838,7 @@ static int dvbdmx_allocate_ts_feed(struct dmx_demux *dmx, feed->demux = demux; feed->pid = 0xffff; feed->peslen = 0xfffa; + feed->buffer_flags = 0; (*ts_feed) = &feed->feed.ts; (*ts_feed)->parent = dmx; @@ -911,14 +958,14 @@ static void prepare_secfilters(struct dvb_demux_feed *dvbdmxfeed) return; do { sf = &f->filter; - doneq = 0; + doneq = false; for (i = 0; i < DVB_DEMUX_MASK_MAX; i++) { mode = sf->filter_mode[i]; mask = sf->filter_mask[i]; f->maskandmode[i] = mask & mode; doneq |= f->maskandnotmode[i] = mask & ~mode; } - f->doneq = doneq ? 1 : 0; + f->doneq = doneq ? true : false; } while ((f = f->next)); } @@ -945,6 +992,7 @@ static int dmx_section_feed_start_filtering(struct dmx_section_feed *feed) dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbufp = 0; dvbdmxfeed->feed.sec.seclen = 0; + dvbdmxfeed->pusi_seen = false; if (!dvbdmx->start_feed) { mutex_unlock(&dvbdmx->mutex); @@ -1049,6 +1097,7 @@ static int dvbdmx_allocate_section_feed(struct dmx_demux *demux, dvbdmxfeed->cb.sec = callback; dvbdmxfeed->demux = dvbdmx; dvbdmxfeed->pid = 0xffff; + dvbdmxfeed->buffer_flags = 0; dvbdmxfeed->feed.sec.secbuf = dvbdmxfeed->feed.sec.secbuf_base; dvbdmxfeed->feed.sec.secbufp = dvbdmxfeed->feed.sec.seclen = 0; dvbdmxfeed->feed.sec.tsfeedp = 0; @@ -1220,12 +1269,25 @@ int dvb_dmx_init(struct dvb_demux *dvbdemux) dvbdemux->cnt_storage = NULL; dvbdemux->users = 0; - dvbdemux->filter = vmalloc(dvbdemux->filternum * sizeof(struct dvb_demux_filter)); +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 18, 0)) + dvbdemux->filter = vmalloc(sizeof(struct dvb_demux_filter) * + dvbdemux->filternum); if (!dvbdemux->filter) return -ENOMEM; - dvbdemux->feed = vmalloc(dvbdemux->feednum * sizeof(struct dvb_demux_feed)); + dvbdemux->feed = vmalloc(sizeof(struct dvb_demux_feed) * + dvbdemux->feednum); +#else + dvbdemux->filter = vmalloc(array_size(sizeof(struct dvb_demux_filter), + dvbdemux->filternum)); + + if (!dvbdemux->filter) + return -ENOMEM; + + dvbdemux->feed = vmalloc(array_size(sizeof(struct dvb_demux_feed), + dvbdemux->feednum)); +#endif if (!dvbdemux->feed) { vfree(dvbdemux->filter); dvbdemux->filter = NULL; diff --git a/dvb-core/dvb_demux.h b/dvb-core/dvb_demux.h deleted file mode 100644 index 6f572ca..0000000 --- a/dvb-core/dvb_demux.h +++ /dev/null @@ -1,145 +0,0 @@ -/* - * dvb_demux.h: DVB kernel demux API - * - * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler - * for convergence integrated media GmbH - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public License - * as published by the Free Software Foundation; either version 2.1 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - */ - -#ifndef _DVB_DEMUX_H_ -#define _DVB_DEMUX_H_ - -#include -#include -#include -#include - -#include "demux.h" - -#define DMX_TYPE_TS 0 -#define DMX_TYPE_SEC 1 -#define DMX_TYPE_PES 2 - -#define DMX_STATE_FREE 0 -#define DMX_STATE_ALLOCATED 1 -#define DMX_STATE_SET 2 -#define DMX_STATE_READY 3 -#define DMX_STATE_GO 4 - -#define DVB_DEMUX_MASK_MAX 18 - -#define MAX_PID 0x1fff - -#define SPEED_PKTS_INTERVAL 50000 - -struct dvb_demux_filter { - struct dmx_section_filter filter; - u8 maskandmode[DMX_MAX_FILTER_SIZE]; - u8 maskandnotmode[DMX_MAX_FILTER_SIZE]; - int doneq; - - struct dvb_demux_filter *next; - struct dvb_demux_feed *feed; - int index; - int state; - int type; - - u16 hw_handle; - struct timer_list timer; -}; - -#define DMX_FEED_ENTRY(pos) list_entry(pos, struct dvb_demux_feed, list_head) - -struct dvb_demux_feed { - union { - struct dmx_ts_feed ts; - struct dmx_section_feed sec; - } feed; - - union { - dmx_ts_cb ts; - dmx_section_cb sec; - } cb; - - struct dvb_demux *demux; - void *priv; - int type; - int state; - u16 pid; - - ktime_t timeout; - struct dvb_demux_filter *filter; - - int ts_type; - enum dmx_ts_pes pes_type; - - int cc; - int pusi_seen; /* prevents feeding of garbage from previous section */ - - u16 peslen; - - struct list_head list_head; - unsigned int index; /* a unique index for each feed (can be used as hardware pid filter index) */ -}; - -struct dvb_demux { - struct dmx_demux dmx; - void *priv; - int filternum; - int feednum; - int (*start_feed)(struct dvb_demux_feed *feed); - int (*stop_feed)(struct dvb_demux_feed *feed); - int (*write_to_decoder)(struct dvb_demux_feed *feed, - const u8 *buf, size_t len); - u32 (*check_crc32)(struct dvb_demux_feed *feed, - const u8 *buf, size_t len); - void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst, - const u8 *src, size_t len); - - int users; -#define MAX_DVB_DEMUX_USERS 10 - struct dvb_demux_filter *filter; - struct dvb_demux_feed *feed; - - struct list_head frontend_list; - - struct dvb_demux_feed *pesfilter[DMX_PES_OTHER]; - u16 pids[DMX_PES_OTHER]; - int playing; - int recording; - -#define DMX_MAX_PID 0x2000 - struct list_head feed_list; - u8 tsbuf[204]; - int tsbufp; - - struct mutex mutex; - spinlock_t lock; - - uint8_t *cnt_storage; /* for TS continuity check */ - - ktime_t speed_last_time; /* for TS speed check */ - uint32_t speed_pkts_cnt; /* for TS speed check */ -}; - -int dvb_dmx_init(struct dvb_demux *dvbdemux); -void dvb_dmx_release(struct dvb_demux *dvbdemux); -void dvb_dmx_swfilter_packets(struct dvb_demux *dvbdmx, const u8 *buf, - size_t count); -void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); -void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, - size_t count); -void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, - size_t count); - -#endif /* _DVB_DEMUX_H_ */ diff --git a/dvb-core/dvb_frontend.c b/dvb-core/dvb_frontend.c index 0d1b8d9..9f6ce4b 100644 --- a/dvb-core/dvb_frontend.c +++ b/dvb-core/dvb_frontend.c @@ -1,25 +1,13 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * dvb_frontend.c: DVB frontend tuning interface/thread * - * * Copyright (C) 1999-2001 Ralph Metzler * Marcus Metzler * Holger Waechtler * for convergence integrated media GmbH * * Copyright (C) 2004 Andrew de Quincey (tuning thread cleanup) - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ /* Enables DVBv3 compatibility bits at the headers */ @@ -45,10 +33,11 @@ #include #include #include +#include #include -#include "dvb_frontend.h" -#include "dvbdev.h" +#include +#include #include static int dvb_frontend_debug; @@ -146,22 +135,39 @@ struct dvb_frontend_private { static void dvb_frontend_invoke_release(struct dvb_frontend *fe, void (*release)(struct dvb_frontend *fe)); -static void dvb_frontend_free(struct kref *ref) +static void __dvb_frontend_free(struct dvb_frontend *fe) { - struct dvb_frontend *fe = - container_of(ref, struct dvb_frontend, refcount); struct dvb_frontend_private *fepriv = fe->frontend_priv; - dvb_free_device(fepriv->dvbdev); + if (fepriv) + dvb_free_device(fepriv->dvbdev); dvb_frontend_invoke_release(fe, fe->ops.release); kfree(fepriv); } +static void dvb_frontend_free(struct kref *ref) +{ + struct dvb_frontend *fe = + container_of(ref, struct dvb_frontend, refcount); + + __dvb_frontend_free(fe); +} + static void dvb_frontend_put(struct dvb_frontend *fe) { - kref_put(&fe->refcount, dvb_frontend_free); + /* call detach before dropping the reference count */ + if (fe->ops.detach) + fe->ops.detach(fe); + /* + * Check if the frontend was registered, as otherwise + * kref was not initialized yet. + */ + if (fe->frontend_priv) + kref_put(&fe->refcount, dvb_frontend_free); + else + __dvb_frontend_free(fe); } static void dvb_frontend_get(struct dvb_frontend *fe) @@ -180,7 +186,7 @@ dtv_property_legacy_params_sync(struct dvb_frontend *fe, static bool has_get_frontend(struct dvb_frontend *fe) { - return fe->ops.get_frontend != NULL; + return fe->ops.get_frontend; } /* @@ -263,11 +269,23 @@ static void dvb_frontend_add_event(struct dvb_frontend *fe, mutex_unlock(&events->mtx); - wake_up_interruptible (&events->wait_queue); + wake_up_interruptible(&events->wait_queue); +} + +static int dvb_frontend_test_event(struct dvb_frontend_private *fepriv, + struct dvb_fe_events *events) +{ + int ret; + + up(&fepriv->sem); + ret = events->eventw != events->eventr; + down(&fepriv->sem); + + return ret; } static int dvb_frontend_get_event(struct dvb_frontend *fe, - struct dvb_frontend_event *event, int flags) + struct dvb_frontend_event *event, int flags) { struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dvb_fe_events *events = &fepriv->events; @@ -285,13 +303,8 @@ static int dvb_frontend_get_event(struct dvb_frontend *fe, if (flags & O_NONBLOCK) return -EWOULDBLOCK; - up(&fepriv->sem); - - ret = wait_event_interruptible (events->wait_queue, - events->eventw != events->eventr); - - if (down_interruptible (&fepriv->sem)) - return -ERESTARTSYS; + ret = wait_event_interruptible(events->wait_queue, + dvb_frontend_test_event(fepriv, events)); if (ret < 0) return ret; @@ -318,8 +331,8 @@ static void dvb_frontend_clear_events(struct dvb_frontend *fe) static void dvb_frontend_init(struct dvb_frontend *fe) { dev_dbg(fe->dvb->device, - "%s: initialising adapter %i frontend %i (%s)...\n", - __func__, fe->dvb->num, fe->id, fe->ops.info.name); + "%s: initialising adapter %i frontend %i (%s)...\n", + __func__, fe->dvb->num, fe->id, fe->ops.info.name); if (fe->ops.init) fe->ops.init(fe); @@ -349,22 +362,25 @@ static void dvb_frontend_swzigzag_update_delay(struct dvb_frontend_private *fepr dev_dbg(fe->dvb->device, "%s:\n", __func__); if (locked) - (fepriv->quality) = (fepriv->quality * 220 + 36*256) / 256; + (fepriv->quality) = (fepriv->quality * 220 + 36 * 256) / 256; else (fepriv->quality) = (fepriv->quality * 220 + 0) / 256; q2 = fepriv->quality - 128; q2 *= q2; - fepriv->delay = fepriv->min_delay + q2 * HZ / (128*128); + fepriv->delay = fepriv->min_delay + q2 * HZ / (128 * 128); } /** - * Performs automatic twiddling of frontend parameters. + * dvb_frontend_swzigzag_autotune - Performs automatic twiddling of frontend + * parameters. * - * @param fe The frontend concerned. - * @param check_wrapped Checks if an iteration has completed. DO NOT SET ON THE FIRST ATTEMPT - * @returns Number of complete iterations that have been performed. + * @fe: The frontend concerned. + * @check_wrapped: Checks if an iteration has completed. + * DO NOT SET ON THE FIRST ATTEMPT. + * + * return: Number of complete iterations that have been performed. */ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wrapped) { @@ -381,7 +397,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra (c->inversion == INVERSION_AUTO)); /* setup parameters correctly */ - while(!ready) { + while (!ready) { /* calculate the lnb_drift */ fepriv->lnb_drift = fepriv->auto_step * fepriv->step_size; @@ -393,7 +409,7 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra } /* perform inversion and +/- zigzag */ - switch(fepriv->auto_sub_step) { + switch (fepriv->auto_sub_step) { case 0: /* try with the current inversion and current drift setting */ ready = 1; @@ -438,11 +454,11 @@ static int dvb_frontend_swzigzag_autotune(struct dvb_frontend *fe, int check_wra return 1; } - dev_dbg(fe->dvb->device, "%s: drift:%i inversion:%i auto_step:%i " \ - "auto_sub_step:%i started_auto_step:%i\n", - __func__, fepriv->lnb_drift, fepriv->inversion, - fepriv->auto_step, fepriv->auto_sub_step, - fepriv->started_auto_step); + dev_dbg(fe->dvb->device, + "%s: drift:%i inversion:%i auto_step:%i auto_sub_step:%i started_auto_step:%i\n", + __func__, fepriv->lnb_drift, fepriv->inversion, + fepriv->auto_step, fepriv->auto_sub_step, + fepriv->started_auto_step); /* set the frontend itself */ c->frequency += fepriv->lnb_drift; @@ -473,7 +489,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) /* if we've got no parameters, just keep idling */ if (fepriv->state & FESTATE_IDLE) { - fepriv->delay = 3*HZ; + fepriv->delay = 3 * HZ; fepriv->quality = 0; return; } @@ -490,7 +506,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) else fepriv->state = FESTATE_TUNED; } - fepriv->delay = 3*HZ; + fepriv->delay = 3 * HZ; fepriv->quality = 0; return; } @@ -579,7 +595,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe) } fepriv->check_wrapped = 1; - /* if we've just retuned, enter the ZIGZAG_FAST state. + /* if we've just re-tuned, enter the ZIGZAG_FAST state. * This ensures we cannot return from an * FE_SET_FRONTEND ioctl before the first frontend tune * occurs */ @@ -646,7 +662,7 @@ static int dvb_frontend_thread(void *data) fepriv->check_wrapped = 0; fepriv->quality = 0; - fepriv->delay = 3*HZ; + fepriv->delay = 3 * HZ; fepriv->status = 0; fepriv->wakeup = 0; fepriv->reinitialise = 0; @@ -658,8 +674,9 @@ static int dvb_frontend_thread(void *data) up(&fepriv->sem); /* is locked when we enter the thread... */ restart: wait_event_interruptible_timeout(fepriv->wait_queue, - dvb_frontend_should_wakeup(fe) || kthread_should_stop() - || freezing(current), + dvb_frontend_should_wakeup(fe) || + kthread_should_stop() || + freezing(current), fepriv->delay); if (kthread_should_stop() || dvb_frontend_is_exiting(fe)) { @@ -808,8 +825,8 @@ static void dvb_frontend_stop(struct dvb_frontend *fe) /* paranoia check in case a signal arrived */ if (fepriv->thread) dev_warn(fe->dvb->device, - "dvb_frontend_stop: warning: thread %p won't exit\n", - fepriv->thread); + "dvb_frontend_stop: warning: thread %p won't exit\n", + fepriv->thread); } /* @@ -846,12 +863,12 @@ static int dvb_frontend_start(struct dvb_frontend *fe) if (fe->exit == DVB_FE_NO_EXIT) return 0; else - dvb_frontend_stop (fe); + dvb_frontend_stop(fe); } if (signal_pending(current)) return -EINTR; - if (down_interruptible (&fepriv->sem)) + if (down_interruptible(&fepriv->sem)) return -EINTR; fepriv->state = FESTATE_IDLE; @@ -860,12 +877,12 @@ static int dvb_frontend_start(struct dvb_frontend *fe) mb(); fe_thread = kthread_run(dvb_frontend_thread, fe, - "kdvb-ad-%i-fe-%i", fe->dvb->num,fe->id); + "kdvb-ad-%i-fe-%i", fe->dvb->num, fe->id); if (IS_ERR(fe_thread)) { ret = PTR_ERR(fe_thread); dev_warn(fe->dvb->device, - "dvb_frontend_start: failed to start kthread (%d)\n", - ret); + "dvb_frontend_start: failed to start kthread (%d)\n", + ret); up(&fepriv->sem); return ret; } @@ -874,20 +891,70 @@ static int dvb_frontend_start(struct dvb_frontend *fe) } static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe, - u32 *freq_min, u32 *freq_max) + u32 *freq_min, u32 *freq_max, + u32 *tolerance) { - *freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min); + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 tuner_min = fe->ops.tuner_ops.info.frequency_min_hz; + u32 tuner_max = fe->ops.tuner_ops.info.frequency_max_hz; + u32 frontend_min = fe->ops.info.frequency_min_hz; + u32 frontend_max = fe->ops.info.frequency_max_hz; - if (fe->ops.info.frequency_max == 0) - *freq_max = fe->ops.tuner_ops.info.frequency_max; - else if (fe->ops.tuner_ops.info.frequency_max == 0) - *freq_max = fe->ops.info.frequency_max; + *freq_min = max(frontend_min, tuner_min); + + if (frontend_max == 0) + *freq_max = tuner_max; + else if (tuner_max == 0) + *freq_max = frontend_max; else - *freq_max = min(fe->ops.info.frequency_max, fe->ops.tuner_ops.info.frequency_max); + *freq_max = min(frontend_max, tuner_max); if (*freq_min == 0 || *freq_max == 0) - dev_warn(fe->dvb->device, "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n", - fe->dvb->num, fe->id); + dev_warn(fe->dvb->device, + "DVB: adapter %i frontend %u frequency limits undefined - fix the driver\n", + fe->dvb->num, fe->id); + + dev_dbg(fe->dvb->device, "frequency interval: tuner: %u...%u, frontend: %u...%u", + tuner_min, tuner_max, frontend_min, frontend_max); + + /* If the standard is for satellite, convert frequencies to kHz */ + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + case SYS_ISDBS: + *freq_min /= kHz; + *freq_max /= kHz; + if (tolerance) + *tolerance = fe->ops.info.frequency_tolerance_hz / kHz; + + break; + default: + if (tolerance) + *tolerance = fe->ops.info.frequency_tolerance_hz; + break; + } +} + +static u32 dvb_frontend_get_stepsize(struct dvb_frontend *fe) +{ + struct dtv_frontend_properties *c = &fe->dtv_property_cache; + u32 fe_step = fe->ops.info.frequency_stepsize_hz; + u32 tuner_step = fe->ops.tuner_ops.info.frequency_step_hz; + u32 step = max(fe_step, tuner_step); + + switch (c->delivery_system) { + case SYS_DVBS: + case SYS_DVBS2: + case SYS_TURBO: + case SYS_ISDBS: + step /= kHz; + break; + default: + break; + } + + return step; } static int dvb_frontend_check_parameters(struct dvb_frontend *fe) @@ -897,12 +964,12 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe) u32 freq_max; /* range check: frequency */ - dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max); + dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max, NULL); if ((freq_min && c->frequency < freq_min) || (freq_max && c->frequency > freq_max)) { dev_warn(fe->dvb->device, "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, c->frequency, - freq_min, freq_max); + fe->dvb->num, fe->id, c->frequency, + freq_min, freq_max); return -EINVAL; } @@ -918,9 +985,9 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe) (fe->ops.info.symbol_rate_max && c->symbol_rate > fe->ops.info.symbol_rate_max)) { dev_warn(fe->dvb->device, "DVB: adapter %i frontend %i symbol rate %u out of range (%u..%u)\n", - fe->dvb->num, fe->id, c->symbol_rate, - fe->ops.info.symbol_rate_min, - fe->ops.info.symbol_rate_max); + fe->dvb->num, fe->id, c->symbol_rate, + fe->ops.info.symbol_rate_min, + fe->ops.info.symbol_rate_max); return -EINVAL; } default: @@ -940,10 +1007,8 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) memset(c, 0, offsetof(struct dtv_frontend_properties, strength)); c->delivery_system = delsys; - c->state = DTV_CLEAR; - dev_dbg(fe->dvb->device, "%s: Clearing cache for delivery system %d\n", - __func__, c->delivery_system); + __func__, c->delivery_system); c->transmission_mode = TRANSMISSION_MODE_AUTO; c->bandwidth_hz = 0; /* AUTO */ @@ -963,7 +1028,7 @@ static int dvb_frontend_clear_cache(struct dvb_frontend *fe) c->isdbt_sb_subchannel = 0; c->isdbt_sb_segment_idx = 0; c->isdbt_sb_segment_count = 0; - c->isdbt_layer_enabled = 0; + c->isdbt_layer_enabled = 7; /* All layers (A,B,C) */ for (i = 0; i < 3; i++) { c->layer[i].fec = FEC_AUTO; c->layer[i].modulation = QAM_AUTO; @@ -1102,39 +1167,6 @@ static struct dtv_cmds_h dtv_cmds[DTV_MAX_COMMAND + 1] = { _DTV_CMD(DTV_STAT_TOTAL_BLOCK_COUNT, 0, 0), }; -static void dtv_property_dump(struct dvb_frontend *fe, - bool is_set, - struct dtv_property *tvp) -{ - int i; - - if (tvp->cmd <= 0 || tvp->cmd > DTV_MAX_COMMAND) { - dev_warn(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x undefined\n", - __func__, - is_set ? "SET" : "GET", - tvp->cmd); - return; - } - - dev_dbg(fe->dvb->device, "%s: %s tvp.cmd = 0x%08x (%s)\n", __func__, - is_set ? "SET" : "GET", - tvp->cmd, - dtv_cmds[tvp->cmd].name); - - if (dtv_cmds[tvp->cmd].buffer) { - dev_dbg(fe->dvb->device, "%s: tvp.u.buffer.len = 0x%02x\n", - __func__, tvp->u.buffer.len); - - for(i = 0; i < tvp->u.buffer.len; i++) - dev_dbg(fe->dvb->device, - "%s: tvp.u.buffer.data[0x%02x] = 0x%02x\n", - __func__, i, tvp->u.buffer.data[i]); - } else { - dev_dbg(fe->dvb->device, "%s: tvp.u.data = 0x%08x\n", __func__, - tvp->u.data); - } -} - /* Synchronise the legacy tuning parameters into the cache, so that demodulator * drivers can use a single set_frontend tuning function, regardless of whether * it's being used for the legacy or new API, reducing code and complexity. @@ -1203,8 +1235,8 @@ static int dtv_property_cache_sync(struct dvb_frontend *fe, break; case DVBV3_UNKNOWN: dev_err(fe->dvb->device, - "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", - __func__, c->delivery_system); + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); return -EINVAL; } @@ -1225,8 +1257,8 @@ dtv_property_legacy_params_sync(struct dvb_frontend *fe, switch (dvbv3_type(c->delivery_system)) { case DVBV3_UNKNOWN: dev_err(fe->dvb->device, - "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", - __func__, c->delivery_system); + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); return -EINVAL; case DVBV3_QPSK: dev_dbg(fe->dvb->device, "%s: Preparing QPSK req\n", __func__); @@ -1283,7 +1315,7 @@ dtv_property_legacy_params_sync(struct dvb_frontend *fe, * dtv_get_frontend - calls a callback for retrieving DTV parameters * @fe: struct dvb_frontend pointer * @c: struct dtv_frontend_properties pointer (DVBv5 cache) - * @p_out struct dvb_frontend_parameters pointer (DVBv3 FE struct) + * @p_out: struct dvb_frontend_parameters pointer (DVBv3 FE struct) * * This routine calls either the DVBv3 or DVBv5 get_frontend call. * If c is not null, it will update the DVBv5 cache struct pointed by it. @@ -1308,17 +1340,15 @@ static int dtv_get_frontend(struct dvb_frontend *fe, return 0; } -static int dvb_frontend_ioctl_legacy(struct file *file, - unsigned int cmd, void *parg); -static int dvb_frontend_ioctl_properties(struct file *file, - unsigned int cmd, void *parg); +static int dvb_frontend_handle_ioctl(struct file *file, + unsigned int cmd, void *parg); static int dtv_property_process_get(struct dvb_frontend *fe, const struct dtv_frontend_properties *c, struct dtv_property *tvp, struct file *file) { - int r, ncaps; + int ncaps; switch(tvp->cmd) { case DTV_ENUM_DELSYS: @@ -1446,6 +1476,11 @@ static int dtv_property_process_get(struct dvb_frontend *fe, tvp->u.data = c->stream_id; break; + /* Physical layer scrambling support */ + case DTV_SCRAMBLING_SEQUENCE_INDEX: + tvp->u.data = c->scrambling_sequence_index; + break; + /* ATSC-MH */ case DTV_ATSCMH_FIC_VER: tvp->u.data = fe->dtv_property_cache.atscmh_fic_ver; @@ -1505,11 +1540,6 @@ static int dtv_property_process_get(struct dvb_frontend *fe, tvp->u.buffer.len = 4; break; - /* Physical layer scrambling support */ - case DTV_SCRAMBLING_SEQUENCE_INDEX: - tvp->u.data = c->scrambling_sequence_index; - break; - /* Fill quality measures */ case DTV_STAT_SIGNAL_STRENGTH: tvp->u.st = c->strength; @@ -1542,14 +1572,18 @@ static int dtv_property_process_get(struct dvb_frontend *fe, return -EINVAL; } - /* Allow the frontend to override outgoing properties */ - if (fe->ops.get_property) { - r = fe->ops.get_property(fe, tvp); - if (r < 0) - return r; - } - - dtv_property_dump(fe, false, tvp); + if (!dtv_cmds[tvp->cmd].buffer) + dev_dbg(fe->dvb->device, + "%s: GET cmd 0x%08x (%s) = 0x%08x\n", + __func__, tvp->cmd, dtv_cmds[tvp->cmd].name, + tvp->u.data); + else + dev_dbg(fe->dvb->device, + "%s: GET cmd 0x%08x (%s) len %d: %*ph\n", + __func__, + tvp->cmd, dtv_cmds[tvp->cmd].name, + tvp->u.buffer.len, + tvp->u.buffer.len, tvp->u.buffer.data); return 0; } @@ -1569,7 +1603,7 @@ static bool is_dvbv3_delsys(u32 delsys) * * Provides emulation for delivery systems that are compatible with the old * DVBv3 call. Among its usages, it provices support for ISDB-T, and allows - * using a DVB-S2 only frontend just like it were a DVB-S, if the frontent + * using a DVB-S2 only frontend just like it were a DVB-S, if the frontend * parameters are compatible with DVB-S spec. */ static int emulate_delivery_system(struct dvb_frontend *fe, u32 delsys) @@ -1653,8 +1687,8 @@ static int dvbv5_set_delivery_system(struct dvb_frontend *fe, if (fe->ops.delsys[ncaps] == desired_system) { c->delivery_system = desired_system; dev_dbg(fe->dvb->device, - "%s: Changing delivery system to %d\n", - __func__, desired_system); + "%s: Changing delivery system to %d\n", + __func__, desired_system); return 0; } ncaps++; @@ -1746,8 +1780,8 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) */ if (is_dvbv3_delsys(c->delivery_system)) { dev_dbg(fe->dvb->device, - "%s: Using delivery system to %d\n", - __func__, c->delivery_system); + "%s: Using delivery system to %d\n", + __func__, c->delivery_system); return 0; } @@ -1772,169 +1806,187 @@ static int dvbv3_set_delivery_system(struct dvb_frontend *fe) return emulate_delivery_system(fe, delsys); } +/** + * dtv_property_process_set - Sets a single DTV property + * @fe: Pointer to &struct dvb_frontend + * @file: Pointer to &struct file + * @cmd: Digital TV command + * @data: An unsigned 32-bits number + * + * This routine assigns the property + * value to the corresponding member of + * &struct dtv_frontend_properties + * + * Returns: + * Zero on success, negative errno on failure. + */ static int dtv_property_process_set(struct dvb_frontend *fe, - struct dtv_property *tvp, - struct file *file) + struct file *file, + u32 cmd, u32 data) { int r = 0; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - /* Allow the frontend to validate incoming properties */ - if (fe->ops.set_property) { - r = fe->ops.set_property(fe, tvp); - if (r < 0) - return r; - } - - dtv_property_dump(fe, true, tvp); - - switch(tvp->cmd) { + /** Dump DTV command name and value*/ + if (!cmd || cmd > DTV_MAX_COMMAND) + dev_warn(fe->dvb->device, "%s: SET cmd 0x%08x undefined\n", + __func__, cmd); + else + dev_dbg(fe->dvb->device, + "%s: SET cmd 0x%08x (%s) to 0x%08x\n", + __func__, cmd, dtv_cmds[cmd].name, data); + switch (cmd) { case DTV_CLEAR: /* * Reset a cache of data specific to the frontend here. This does - * not affect hardware. + * not effect hardware. */ dvb_frontend_clear_cache(fe); break; case DTV_TUNE: - /* interpret the cache of data, build either a traditional frontend - * tunerequest so we can pass validation in the FE_SET_FRONTEND - * ioctl. + /* + * Use the cached Digital TV properties to tune the + * frontend */ - c->state = tvp->cmd; - dev_dbg(fe->dvb->device, "%s: Finalised property cache\n", - __func__); + dev_dbg(fe->dvb->device, + "%s: Setting the frontend from property cache\n", + __func__); r = dtv_set_frontend(fe); break; case DTV_FREQUENCY: - c->frequency = tvp->u.data; + c->frequency = data; break; case DTV_MODULATION: - c->modulation = tvp->u.data; + c->modulation = data; break; case DTV_BANDWIDTH_HZ: - c->bandwidth_hz = tvp->u.data; + c->bandwidth_hz = data; break; case DTV_INVERSION: - c->inversion = tvp->u.data; + c->inversion = data; break; case DTV_SYMBOL_RATE: - c->symbol_rate = tvp->u.data; + c->symbol_rate = data; break; case DTV_INNER_FEC: - c->fec_inner = tvp->u.data; + c->fec_inner = data; break; case DTV_PILOT: - c->pilot = tvp->u.data; + c->pilot = data; break; case DTV_ROLLOFF: - c->rolloff = tvp->u.data; + c->rolloff = data; break; case DTV_DELIVERY_SYSTEM: - r = dvbv5_set_delivery_system(fe, tvp->u.data); + r = dvbv5_set_delivery_system(fe, data); break; case DTV_VOLTAGE: - c->voltage = tvp->u.data; - r = dvb_frontend_ioctl_legacy(file, FE_SET_VOLTAGE, - (void *)c->voltage); + c->voltage = data; + r = dvb_frontend_handle_ioctl(file, FE_SET_VOLTAGE, + (void *)c->voltage); break; case DTV_TONE: - c->sectone = tvp->u.data; - r = dvb_frontend_ioctl_legacy(file, FE_SET_TONE, - (void *)c->sectone); + c->sectone = data; + r = dvb_frontend_handle_ioctl(file, FE_SET_TONE, + (void *)c->sectone); break; case DTV_CODE_RATE_HP: - c->code_rate_HP = tvp->u.data; + c->code_rate_HP = data; break; case DTV_CODE_RATE_LP: - c->code_rate_LP = tvp->u.data; + c->code_rate_LP = data; break; case DTV_GUARD_INTERVAL: - c->guard_interval = tvp->u.data; + c->guard_interval = data; break; case DTV_TRANSMISSION_MODE: - c->transmission_mode = tvp->u.data; + c->transmission_mode = data; break; case DTV_HIERARCHY: - c->hierarchy = tvp->u.data; + c->hierarchy = data; break; case DTV_INTERLEAVING: - c->interleaving = tvp->u.data; + c->interleaving = data; break; /* ISDB-T Support here */ case DTV_ISDBT_PARTIAL_RECEPTION: - c->isdbt_partial_reception = tvp->u.data; + c->isdbt_partial_reception = data; break; case DTV_ISDBT_SOUND_BROADCASTING: - c->isdbt_sb_mode = tvp->u.data; + c->isdbt_sb_mode = data; break; case DTV_ISDBT_SB_SUBCHANNEL_ID: - c->isdbt_sb_subchannel = tvp->u.data; + c->isdbt_sb_subchannel = data; break; case DTV_ISDBT_SB_SEGMENT_IDX: - c->isdbt_sb_segment_idx = tvp->u.data; + c->isdbt_sb_segment_idx = data; break; case DTV_ISDBT_SB_SEGMENT_COUNT: - c->isdbt_sb_segment_count = tvp->u.data; + c->isdbt_sb_segment_count = data; break; case DTV_ISDBT_LAYER_ENABLED: - c->isdbt_layer_enabled = tvp->u.data; + c->isdbt_layer_enabled = data; break; case DTV_ISDBT_LAYERA_FEC: - c->layer[0].fec = tvp->u.data; + c->layer[0].fec = data; break; case DTV_ISDBT_LAYERA_MODULATION: - c->layer[0].modulation = tvp->u.data; + c->layer[0].modulation = data; break; case DTV_ISDBT_LAYERA_SEGMENT_COUNT: - c->layer[0].segment_count = tvp->u.data; + c->layer[0].segment_count = data; break; case DTV_ISDBT_LAYERA_TIME_INTERLEAVING: - c->layer[0].interleaving = tvp->u.data; + c->layer[0].interleaving = data; break; case DTV_ISDBT_LAYERB_FEC: - c->layer[1].fec = tvp->u.data; + c->layer[1].fec = data; break; case DTV_ISDBT_LAYERB_MODULATION: - c->layer[1].modulation = tvp->u.data; + c->layer[1].modulation = data; break; case DTV_ISDBT_LAYERB_SEGMENT_COUNT: - c->layer[1].segment_count = tvp->u.data; + c->layer[1].segment_count = data; break; case DTV_ISDBT_LAYERB_TIME_INTERLEAVING: - c->layer[1].interleaving = tvp->u.data; + c->layer[1].interleaving = data; break; case DTV_ISDBT_LAYERC_FEC: - c->layer[2].fec = tvp->u.data; + c->layer[2].fec = data; break; case DTV_ISDBT_LAYERC_MODULATION: - c->layer[2].modulation = tvp->u.data; + c->layer[2].modulation = data; break; case DTV_ISDBT_LAYERC_SEGMENT_COUNT: - c->layer[2].segment_count = tvp->u.data; + c->layer[2].segment_count = data; break; case DTV_ISDBT_LAYERC_TIME_INTERLEAVING: - c->layer[2].interleaving = tvp->u.data; + c->layer[2].interleaving = data; break; /* Multistream support */ case DTV_STREAM_ID: case DTV_DVBT2_PLP_ID_LEGACY: - c->stream_id = tvp->u.data; + c->stream_id = data; + break; + + /* Physical layer scrambling support */ + case DTV_SCRAMBLING_SEQUENCE_INDEX: + c->scrambling_sequence_index = data; break; /* ATSC-MH */ case DTV_ATSCMH_PARADE_ID: - fe->dtv_property_cache.atscmh_parade_id = tvp->u.data; + fe->dtv_property_cache.atscmh_parade_id = data; break; case DTV_ATSCMH_RS_FRAME_ENSEMBLE: - fe->dtv_property_cache.atscmh_rs_frame_ensemble = tvp->u.data; + fe->dtv_property_cache.atscmh_rs_frame_ensemble = data; break; case DTV_LNA: - c->lna = tvp->u.data; + c->lna = data; if (fe->ops.set_lna) r = fe->ops.set_lna(fe); if (r < 0) @@ -1942,16 +1994,11 @@ static int dtv_property_process_set(struct dvb_frontend *fe, break; case DTV_INPUT: - c->input = tvp->u.data; + c->input = data; if (fe->ops.set_input) r = fe->ops.set_input(fe, c->input); break; - /* Physical layer scrambling support */ - case DTV_SCRAMBLING_SEQUENCE_INDEX: - c->scrambling_sequence_index = tvp->u.data; - break; - default: return -EINVAL; } @@ -1959,14 +2006,13 @@ static int dtv_property_process_set(struct dvb_frontend *fe, return r; } -static int dvb_frontend_ioctl(struct file *file, - unsigned int cmd, void *parg) +static int dvb_frontend_do_ioctl(struct file *file, unsigned int cmd, + void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; struct dvb_frontend_private *fepriv = fe->frontend_priv; - int err = -EOPNOTSUPP; + int err; dev_dbg(fe->dvb->device, "%s: (%d)\n", __func__, _IOC_NR(cmd)); if (down_interruptible(&fepriv->sem)) @@ -1977,74 +2023,125 @@ static int dvb_frontend_ioctl(struct file *file, return -ENODEV; } - if ((file->f_flags & O_ACCMODE) == O_RDONLY && - (_IOC_DIR(cmd) != _IOC_READ || cmd == FE_GET_EVENT || - cmd == FE_DISEQC_RECV_SLAVE_REPLY)) { + /* + * If the frontend is opened in read-only mode, only the ioctls + * that don't interfere with the tune logic should be accepted. + * That allows an external application to monitor the DVB QoS and + * statistics parameters. + * + * That matches all _IOR() ioctls, except for two special cases: + * - FE_GET_EVENT is part of the tuning logic on a DVB application; + * - FE_DISEQC_RECV_SLAVE_REPLY is part of DiSEqC 2.0 + * setup + * So, those two ioctls should also return -EPERM, as otherwise + * reading from them would interfere with a DVB tune application + */ + if ((file->f_flags & O_ACCMODE) == O_RDONLY + && (_IOC_DIR(cmd) != _IOC_READ + || cmd == FE_GET_EVENT + || cmd == FE_DISEQC_RECV_SLAVE_REPLY)) { up(&fepriv->sem); return -EPERM; } - if ((cmd == FE_SET_PROPERTY) || (cmd == FE_GET_PROPERTY)) - err = dvb_frontend_ioctl_properties(file, cmd, parg); - else { - c->state = DTV_UNDEFINED; - err = dvb_frontend_ioctl_legacy(file, cmd, parg); - } + err = dvb_frontend_handle_ioctl(file, cmd, parg); up(&fepriv->sem); return err; } -static int dvb_frontend_ioctl_properties(struct file *file, - unsigned int cmd, void *parg) +static long dvb_frontend_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct dvb_device *dvbdev = file->private_data; + + if (!dvbdev) + return -ENODEV; + + return dvb_usercopy(file, cmd, arg, dvb_frontend_do_ioctl); +} + +#ifdef CONFIG_COMPAT +struct compat_dtv_property { + __u32 cmd; + __u32 reserved[3]; + union { + __u32 data; + struct dtv_fe_stats st; + struct { + __u8 data[32]; + __u32 len; + __u32 reserved1[3]; + compat_uptr_t reserved2; + } buffer; + } u; + int result; +} __attribute__ ((packed)); + +struct compat_dtv_properties { + __u32 num; + compat_uptr_t props; +}; + +#define COMPAT_FE_SET_PROPERTY _IOW('o', 82, struct compat_dtv_properties) +#define COMPAT_FE_GET_PROPERTY _IOR('o', 83, struct compat_dtv_properties) + +static int dvb_frontend_handle_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; - struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int err = 0; + int i, err = 0; - struct dtv_properties *tvps = parg; - struct dtv_property *tvp = NULL; - int i; + if (cmd == COMPAT_FE_SET_PROPERTY) { + struct compat_dtv_properties prop, *tvps = NULL; + struct compat_dtv_property *tvp = NULL; - dev_dbg(fe->dvb->device, "%s:\n", __func__); + if (copy_from_user(&prop, compat_ptr(arg), sizeof(prop))) + return -EFAULT; - if (cmd == FE_SET_PROPERTY) { - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); + tvps = ∝ - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + tvp = memdup_user(compat_ptr(tvps->props), tvps->num * sizeof(*tvp)); if (IS_ERR(tvp)) return PTR_ERR(tvp); for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_set(fe, tvp + i, file); - if (err < 0) - goto out; - (tvp + i)->result = err; + err = dtv_property_process_set(fe, file, + (tvp + i)->cmd, + (tvp + i)->u.data); + if (err < 0) { + kfree(tvp); + return err; + } } - - if (c->state == DTV_TUNE) - dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__); - - } else if (cmd == FE_GET_PROPERTY) { + kfree(tvp); + } else if (cmd == COMPAT_FE_GET_PROPERTY) { + struct compat_dtv_properties prop, *tvps = NULL; + struct compat_dtv_property *tvp = NULL; struct dtv_frontend_properties getp = fe->dtv_property_cache; - dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num); - dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props); + if (copy_from_user(&prop, compat_ptr(arg), sizeof(prop))) + return -EFAULT; - /* Put an arbitrary limit on the number of messages that can - * be sent at once */ - if ((tvps->num == 0) || (tvps->num > DTV_IOCTL_MAX_MSGS)) + tvps = ∝ + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) return -EINVAL; - tvp = memdup_user(tvps->props, tvps->num * sizeof(*tvp)); + tvp = memdup_user(compat_ptr(tvps->props), tvps->num * sizeof(*tvp)); if (IS_ERR(tvp)) return PTR_ERR(tvp); @@ -2056,30 +2153,53 @@ static int dvb_frontend_ioctl_properties(struct file *file, */ if (fepriv->state != FESTATE_IDLE) { err = dtv_get_frontend(fe, &getp, NULL); - if (err < 0) - goto out; + if (err < 0) { + kfree(tvp); + return err; + } } for (i = 0; i < tvps->num; i++) { - err = dtv_property_process_get(fe, &getp, tvp + i, file); - if (err < 0) - goto out; - (tvp + i)->result = err; + err = dtv_property_process_get( + fe, &getp, (struct dtv_property *)(tvp + i), file); + if (err < 0) { + kfree(tvp); + return err; + } } - if (copy_to_user((void __user *)tvps->props, tvp, - tvps->num * sizeof(struct dtv_property))) { - err = -EFAULT; - goto out; + if (copy_to_user((void __user *)compat_ptr(tvps->props), tvp, + tvps->num * sizeof(struct compat_dtv_property))) { + kfree(tvp); + return -EFAULT; } + kfree(tvp); + } - } else - err = -EOPNOTSUPP; - -out: - kfree(tvp); return err; } +static long dvb_frontend_compat_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct dvb_device *dvbdev = file->private_data; + struct dvb_frontend *fe = dvbdev->priv; + struct dvb_frontend_private *fepriv = fe->frontend_priv; + int err; + + if (cmd == COMPAT_FE_SET_PROPERTY || cmd == COMPAT_FE_GET_PROPERTY) { + if (down_interruptible(&fepriv->sem)) + return -ERESTARTSYS; + + err = dvb_frontend_handle_compat_ioctl(file, cmd, arg); + + up(&fepriv->sem); + return err; + } + + return dvb_frontend_ioctl(file, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + static int dtv_set_frontend(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; @@ -2148,9 +2268,8 @@ static int dtv_set_frontend(struct dvb_frontend *fe) default: break; } - if (!c->bandwidth_hz) - if (rolloff) - c->bandwidth_hz = mult_frac(c->symbol_rate, rolloff, 100); + if (rolloff) + c->bandwidth_hz = mult_frac(c->symbol_rate, rolloff, 100); /* force auto frequency inversion if requested */ if (dvb_force_auto_inversion) @@ -2187,8 +2306,8 @@ static int dtv_set_frontend(struct dvb_frontend *fe) case SYS_ISDBT: case SYS_DTMB: fepriv->min_delay = HZ / 20; - fepriv->step_size = fe->ops.info.frequency_stepsize * 2; - fepriv->max_drift = (fe->ops.info.frequency_stepsize * 2) + 1; + fepriv->step_size = dvb_frontend_get_stepsize(fe) * 2; + fepriv->max_drift = (dvb_frontend_get_stepsize(fe) * 2) + 1; break; default: /* @@ -2218,21 +2337,144 @@ static int dtv_set_frontend(struct dvb_frontend *fe) } -static int dvb_frontend_ioctl_legacy(struct file *file, - unsigned int cmd, void *parg) +static int dvb_get_property(struct dvb_frontend *fe, struct file *file, + struct dtv_properties *tvps) +{ + struct dvb_frontend_private *fepriv = fe->frontend_priv; + struct dtv_property *tvp = NULL; + struct dtv_frontend_properties getp; + int i, err; + + memcpy(&getp, &fe->dtv_property_cache, sizeof(getp)); + + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || tvps->num > DTV_IOCTL_MAX_MSGS) + return -EINVAL; + + tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); + if (IS_ERR(tvp)) + return PTR_ERR(tvp); + + /* + * Let's use our own copy of property cache, in order to + * avoid mangling with DTV zigzag logic, as drivers might + * return crap, if they don't check if the data is available + * before updating the properties cache. + */ + if (fepriv->state != FESTATE_IDLE) { + err = dtv_get_frontend(fe, &getp, NULL); + if (err < 0) + goto out; + } + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_get(fe, &getp, + tvp + i, file); + if (err < 0) + goto out; + } + + if (copy_to_user((void __user *)tvps->props, tvp, + tvps->num * sizeof(struct dtv_property))) { + err = -EFAULT; + goto out; + } + + err = 0; +out: + kfree(tvp); + return err; +} + +static int dvb_get_frontend(struct dvb_frontend *fe, + struct dvb_frontend_parameters *p_out) +{ + struct dtv_frontend_properties getp; + + /* + * Let's use our own copy of property cache, in order to + * avoid mangling with DTV zigzag logic, as drivers might + * return crap, if they don't check if the data is available + * before updating the properties cache. + */ + memcpy(&getp, &fe->dtv_property_cache, sizeof(getp)); + + return dtv_get_frontend(fe, &getp, p_out); +} + +static int dvb_frontend_handle_ioctl(struct file *file, + unsigned int cmd, void *parg) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; struct dvb_frontend_private *fepriv = fe->frontend_priv; struct dtv_frontend_properties *c = &fe->dtv_property_cache; - int err = -EOPNOTSUPP; + int i, err = -ENOTSUPP; + + dev_dbg(fe->dvb->device, "%s:\n", __func__); switch (cmd) { - case FE_GET_INFO: { - struct dvb_frontend_info* info = parg; + case FE_SET_PROPERTY: { + struct dtv_properties *tvps = parg; + struct dtv_property *tvp = NULL; - memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info)); - dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max); + dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", + __func__, tvps->num); + dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", + __func__, tvps->props); + + /* + * Put an arbitrary limit on the number of messages that can + * be sent at once + */ + if (!tvps->num || (tvps->num > DTV_IOCTL_MAX_MSGS)) + return -EINVAL; + + tvp = memdup_user((void __user *)tvps->props, tvps->num * sizeof(*tvp)); + if (IS_ERR(tvp)) + return PTR_ERR(tvp); + + for (i = 0; i < tvps->num; i++) { + err = dtv_property_process_set(fe, file, + (tvp + i)->cmd, + (tvp + i)->u.data); + if (err < 0) { + kfree(tvp); + return err; + } + } + kfree(tvp); + err = 0; + break; + } + case FE_GET_PROPERTY: + err = dvb_get_property(fe, file, parg); + break; + + case FE_GET_INFO: { + struct dvb_frontend_info *info = parg; + memset(info, 0, sizeof(*info)); + +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)) + strscpy(info->name, fe->ops.info.name, sizeof(info->name)); +#else + strncpy(info->name, fe->ops.info.name, sizeof(info->name)); +#endif + info->symbol_rate_min = fe->ops.info.symbol_rate_min; + info->symbol_rate_max = fe->ops.info.symbol_rate_max; + info->symbol_rate_tolerance = fe->ops.info.symbol_rate_tolerance; + info->caps = fe->ops.info.caps; + info->frequency_stepsize = dvb_frontend_get_stepsize(fe); + dvb_frontend_get_frequency_limits(fe, &info->frequency_min, + &info->frequency_max, + &info->frequency_tolerance); /* * Associate the 4 delivery systems supported by DVBv3 @@ -2260,12 +2502,12 @@ static int dvb_frontend_ioctl_legacy(struct file *file, break; default: dev_err(fe->dvb->device, - "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", - __func__, c->delivery_system); - fe->ops.info.type = FE_OFDM; + "%s: doesn't know how to handle a DVBv3 call to delivery system %i\n", + __func__, c->delivery_system); + info->type = FE_OFDM; } dev_dbg(fe->dvb->device, "%s: current delivery system on cache: %d, V3 type: %d\n", - __func__, c->delivery_system, fe->ops.info.type); + __func__, c->delivery_system, info->type); /* Set CAN_INVERSION_AUTO bit on in other than oneshot mode */ if (!(fepriv->tune_mode_flags & FE_TUNE_MODE_ONESHOT)) @@ -2281,7 +2523,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, * that user get signal state from previous tuning */ if (fepriv->state == FESTATE_RETUNE || fepriv->state == FESTATE_ERROR) { - err=0; + err = 0; *status = 0; break; } @@ -2291,42 +2533,6 @@ static int dvb_frontend_ioctl_legacy(struct file *file, break; } - case FE_READ_BER: - if (fe->ops.read_ber) { - if (fepriv->thread) - err = fe->ops.read_ber(fe, (__u32 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_SIGNAL_STRENGTH: - if (fe->ops.read_signal_strength) { - if (fepriv->thread) - err = fe->ops.read_signal_strength(fe, (__u16 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_SNR: - if (fe->ops.read_snr) { - if (fepriv->thread) - err = fe->ops.read_snr(fe, (__u16 *) parg); - else - err = -EAGAIN; - } - break; - - case FE_READ_UNCORRECTED_BLOCKS: - if (fe->ops.read_ucblocks) { - if (fepriv->thread) - err = fe->ops.read_ucblocks(fe, (__u32 *) parg); - else - err = -EAGAIN; - } - break; - case FE_DISEQC_RESET_OVERLOAD: if (fe->ops.diseqc_reset_overload) { err = fe->ops.diseqc_reset_overload(fe); @@ -2378,6 +2584,22 @@ static int dvb_frontend_ioctl_legacy(struct file *file, } break; + case FE_DISEQC_RECV_SLAVE_REPLY: + if (fe->ops.diseqc_recv_slave_reply) + err = fe->ops.diseqc_recv_slave_reply(fe, parg); + break; + + case FE_ENABLE_HIGH_LNB_VOLTAGE: + if (fe->ops.enable_high_lnb_voltage) + err = fe->ops.enable_high_lnb_voltage(fe, (long)parg); + break; + + case FE_SET_FRONTEND_TUNE_MODE: + fepriv->tune_mode_flags = (unsigned long)parg; + err = 0; + break; + /* DEPRECATED dish control ioctls */ + case FE_DISHNETWORK_SEND_LEGACY_CMD: if (fe->ops.dishnetwork_send_legacy_command) { err = fe->ops.dishnetwork_send_legacy_command(fe, @@ -2401,14 +2623,15 @@ static int dvb_frontend_ioctl_legacy(struct file *file, * initialization, so parg is 8 bits and does not * include the initialization or start bit */ - unsigned long swcmd = ((unsigned long) parg) << 1; + unsigned long swcmd = ((unsigned long)parg) << 1; ktime_t nexttime; ktime_t tv[10]; int i; u8 last = 1; + if (dvb_frontend_debug) - dprintk("%s switch command: 0x%04lx\n", - __func__, swcmd); + dprintk("switch command: 0x%04lx\n", + swcmd); nexttime = ktime_get_boottime(); if (dvb_frontend_debug) tv[0] = nexttime; @@ -2420,7 +2643,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file, for (i = 0; i < 9; i++) { if (dvb_frontend_debug) - tv[i+1] = ktime_get_boottime(); + tv[i + 1] = ktime_get_boottime(); if ((swcmd & 0x01) != last) { /* set voltage to (last ? 13V : 18V) */ fe->ops.set_voltage(fe, (last) ? SEC_VOLTAGE_13 : SEC_VOLTAGE_18); @@ -2431,11 +2654,11 @@ static int dvb_frontend_ioctl_legacy(struct file *file, dvb_frontend_sleep_until(&nexttime, 8000); } if (dvb_frontend_debug) { - dprintk("%s(%d): switch delay (should be 32k followed by all 8k)\n", - __func__, fe->dvb->num); + dprintk("(adapter %d): switch delay (should be 32k followed by all 8k)\n", + fe->dvb->num); for (i = 1; i < 10; i++) pr_info("%d: %d\n", i, - (int) ktime_us_delta(tv[i], tv[i-1])); + (int)ktime_us_delta(tv[i], tv[i - 1])); } err = 0; fepriv->state = FESTATE_DISEQC; @@ -2443,16 +2666,46 @@ static int dvb_frontend_ioctl_legacy(struct file *file, } break; - case FE_DISEQC_RECV_SLAVE_REPLY: - if (fe->ops.diseqc_recv_slave_reply) - err = fe->ops.diseqc_recv_slave_reply(fe, (struct dvb_diseqc_slave_reply*) parg); + /* DEPRECATED statistics ioctls */ + + case FE_READ_BER: + if (fe->ops.read_ber) { + if (fepriv->thread) + err = fe->ops.read_ber(fe, parg); + else + err = -EAGAIN; + } break; - case FE_ENABLE_HIGH_LNB_VOLTAGE: - if (fe->ops.enable_high_lnb_voltage) - err = fe->ops.enable_high_lnb_voltage(fe, (long) parg); + case FE_READ_SIGNAL_STRENGTH: + if (fe->ops.read_signal_strength) { + if (fepriv->thread) + err = fe->ops.read_signal_strength(fe, parg); + else + err = -EAGAIN; + } break; + case FE_READ_SNR: + if (fe->ops.read_snr) { + if (fepriv->thread) + err = fe->ops.read_snr(fe, parg); + else + err = -EAGAIN; + } + break; + + case FE_READ_UNCORRECTED_BLOCKS: + if (fe->ops.read_ucblocks) { + if (fepriv->thread) + err = fe->ops.read_ucblocks(fe, parg); + else + err = -EAGAIN; + } + break; + + /* DEPRECATED DVBv3 ioctls */ + case FE_SET_FRONTEND: err = dvbv3_set_delivery_system(fe); if (err) @@ -2463,33 +2716,34 @@ static int dvb_frontend_ioctl_legacy(struct file *file, break; err = dtv_set_frontend(fe); break; + case FE_GET_EVENT: - err = dvb_frontend_get_event (fe, parg, file->f_flags); + err = dvb_frontend_get_event(fe, parg, file->f_flags); break; - case FE_GET_FRONTEND: { - struct dtv_frontend_properties getp = fe->dtv_property_cache; + case FE_GET_FRONTEND: + err = dvb_get_frontend(fe, parg); + break; - /* - * Let's use our own copy of property cache, in order to - * avoid mangling with DTV zigzag logic, as drivers might - * return crap, if they don't check if the data is available - * before updating the properties cache. - */ - err = dtv_get_frontend(fe, &getp, parg); - break; - } - case FE_SET_FRONTEND_TUNE_MODE: - fepriv->tune_mode_flags = (unsigned long) parg; - err = 0; - break; - } + default: + return -ENOTSUPP; + } /* switch */ return err; } +#if (LINUX_VERSION_CODE < KERNEL_VERSION(4, 16, 0)) +typedef unsigned int __poll_t; +#define EPOLLIN POLLIN +#define EPOLLERR POLLERR +#define EPOLLPRI POLLPRI +#define EPOLLRDNORM POLLRDNORM +#define EPOLLWRNORM POLLWRNORM +#define EPOLLOUT POLLOUT +#endif -static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) + +static __poll_t dvb_frontend_poll(struct file *file, struct poll_table_struct *wait) { struct dvb_device *dvbdev = file->private_data; struct dvb_frontend *fe = dvbdev->priv; @@ -2497,10 +2751,10 @@ static unsigned int dvb_frontend_poll(struct file *file, struct poll_table_struc dev_dbg_ratelimited(fe->dvb->device, "%s:\n", __func__); - poll_wait (file, &fepriv->events.wait_queue, wait); + poll_wait(file, &fepriv->events.wait_queue, wait); if (fepriv->events.eventw != fepriv->events.eventr) - return (POLLIN | POLLRDNORM | POLLPRI); + return (EPOLLIN | EPOLLRDNORM | EPOLLPRI); return 0; } @@ -2518,9 +2772,9 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) return -ENODEV; if (adapter->mfe_shared) { - mutex_lock (&adapter->mfe_lock); + mutex_lock(&adapter->mfe_lock); - if (adapter->mfe_dvbdev == NULL) + if (!adapter->mfe_dvbdev) adapter->mfe_dvbdev = dvbdev; else if (adapter->mfe_dvbdev != dvbdev) { @@ -2532,23 +2786,23 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) *mfepriv = mfe->frontend_priv; int mferetry = (dvb_mfe_wait_time << 1); - mutex_unlock (&adapter->mfe_lock); + mutex_unlock(&adapter->mfe_lock); while (mferetry-- && (mfedev->users != -1 || - mfepriv->thread != NULL)) { - if(msleep_interruptible(500)) { - if(signal_pending(current)) + mfepriv->thread)) { + if (msleep_interruptible(500)) { + if (signal_pending(current)) return -EINTR; } } - mutex_lock (&adapter->mfe_lock); - if(adapter->mfe_dvbdev != dvbdev) { + mutex_lock(&adapter->mfe_lock); + if (adapter->mfe_dvbdev != dvbdev) { mfedev = adapter->mfe_dvbdev; mfe = mfedev->priv; mfepriv = mfe->frontend_priv; if (mfedev->users != -1 || - mfepriv->thread != NULL) { - mutex_unlock (&adapter->mfe_lock); + mfepriv->thread) { + mutex_unlock(&adapter->mfe_lock); return -EBUSY; } adapter->mfe_dvbdev = dvbdev; @@ -2569,7 +2823,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) fepriv->reinitialise = 1; } - if ((ret = dvb_generic_open (inode, file)) < 0) + if ((ret = dvb_generic_open(inode, file)) < 0) goto err1; if ((file->f_flags & O_ACCMODE) != O_RDONLY) { @@ -2579,6 +2833,7 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) fepriv->voltage = -1; #ifdef CONFIG_MEDIA_CONTROLLER_DVB + mutex_lock(&fe->dvb->mdev_lock); if (fe->dvb->mdev) { mutex_lock(&fe->dvb->mdev->graph_mutex); if (fe->dvb->mdev->enable_source) @@ -2587,13 +2842,15 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) &fepriv->pipe); mutex_unlock(&fe->dvb->mdev->graph_mutex); if (ret) { + mutex_unlock(&fe->dvb->mdev_lock); dev_err(fe->dvb->device, "Tuner is busy. Error %d\n", ret); goto err2; } } + mutex_unlock(&fe->dvb->mdev_lock); #endif - ret = dvb_frontend_start (fe); + ret = dvb_frontend_start(fe); if (ret) goto err3; @@ -2604,17 +2861,19 @@ static int dvb_frontend_open(struct inode *inode, struct file *file) dvb_frontend_get(fe); if (adapter->mfe_shared) - mutex_unlock (&adapter->mfe_lock); + mutex_unlock(&adapter->mfe_lock); return ret; err3: #ifdef CONFIG_MEDIA_CONTROLLER_DVB + mutex_lock(&fe->dvb->mdev_lock); if (fe->dvb->mdev) { mutex_lock(&fe->dvb->mdev->graph_mutex); if (fe->dvb->mdev->disable_source) fe->dvb->mdev->disable_source(dvbdev->entity); mutex_unlock(&fe->dvb->mdev->graph_mutex); } + mutex_unlock(&fe->dvb->mdev_lock); err2: #endif dvb_generic_release(inode, file); @@ -2623,7 +2882,7 @@ err1: fe->ops.ts_bus_ctrl(fe, 0); err0: if (adapter->mfe_shared) - mutex_unlock (&adapter->mfe_lock); + mutex_unlock(&adapter->mfe_lock); return ret; } @@ -2641,17 +2900,19 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) mb(); } - ret = dvb_generic_release (inode, file); + ret = dvb_generic_release(inode, file); if (dvbdev->users == -1) { wake_up(&fepriv->wait_queue); #ifdef CONFIG_MEDIA_CONTROLLER_DVB + mutex_lock(&fe->dvb->mdev_lock); if (fe->dvb->mdev) { mutex_lock(&fe->dvb->mdev->graph_mutex); if (fe->dvb->mdev->disable_source) fe->dvb->mdev->disable_source(dvbdev->entity); mutex_unlock(&fe->dvb->mdev->graph_mutex); } + mutex_unlock(&fe->dvb->mdev_lock); #endif if (fe->exit != DVB_FE_NO_EXIT) wake_up(&dvbdev->wait_queue); @@ -2666,7 +2927,10 @@ static int dvb_frontend_release(struct inode *inode, struct file *file) static const struct file_operations dvb_frontend_fops = { .owner = THIS_MODULE, - .unlocked_ioctl = dvb_generic_ioctl, + .unlocked_ioctl = dvb_frontend_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = dvb_frontend_compat_ioctl, +#endif .poll = dvb_frontend_poll, .open = dvb_frontend_open, .release = dvb_frontend_release, @@ -2678,7 +2942,7 @@ int dvb_frontend_suspend(struct dvb_frontend *fe) int ret = 0; dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, - fe->id); + fe->id); if (fe->ops.tuner_ops.suspend) ret = fe->ops.tuner_ops.suspend(fe); @@ -2698,7 +2962,7 @@ int dvb_frontend_resume(struct dvb_frontend *fe) int ret = 0; dev_dbg(fe->dvb->device, "%s: adap=%d fe=%d\n", __func__, fe->dvb->num, - fe->id); + fe->id); fe->exit = DVB_FE_DEVICE_RESUME; if (fe->ops.init) @@ -2722,19 +2986,18 @@ int dvb_frontend_resume(struct dvb_frontend *fe) } EXPORT_SYMBOL(dvb_frontend_resume); -int dvb_register_frontend(struct dvb_adapter* dvb, - struct dvb_frontend* fe) +int dvb_register_frontend(struct dvb_adapter *dvb, + struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv; const struct dvb_device dvbdev_template = { .users = ~0, .writers = 1, - .readers = (~0)-1, + .readers = (~0) - 1, .fops = &dvb_frontend_fops, #if defined(CONFIG_MEDIA_CONTROLLER_DVB) .name = fe->ops.info.name, #endif - .kernel_ioctl = dvb_frontend_ioctl }; dev_dbg(dvb->device, "%s:\n", __func__); @@ -2743,7 +3006,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb, return -ERESTARTSYS; fe->frontend_priv = kzalloc(sizeof(struct dvb_frontend_private), GFP_KERNEL); - if (fe->frontend_priv == NULL) { + if (!fe->frontend_priv) { mutex_unlock(&frontend_mutex); return -ENOMEM; } @@ -2759,18 +3022,18 @@ int dvb_register_frontend(struct dvb_adapter* dvb, dvb_frontend_get(fe); sema_init(&fepriv->sem, 1); - init_waitqueue_head (&fepriv->wait_queue); - init_waitqueue_head (&fepriv->events.wait_queue); + init_waitqueue_head(&fepriv->wait_queue); + init_waitqueue_head(&fepriv->events.wait_queue); mutex_init(&fepriv->events.mtx); fe->dvb = dvb; fepriv->inversion = INVERSION_OFF; - dvb_register_device (fe->dvb, &fepriv->dvbdev, &dvbdev_template, - fe, DVB_DEVICE_FRONTEND, 0); - dev_info(fe->dvb->device, - "DVB: registering adapter %i frontend %i (%s)...\n", - fe->dvb->num, fepriv->dvbdev->id, fe->ops.info.name); + "DVB: registering adapter %i frontend %i (%s)...\n", + fe->dvb->num, fe->id, fe->ops.info.name); + + dvb_register_device(fe->dvb, &fepriv->dvbdev, &dvbdev_template, + fe, DVB_DEVICE_FRONTEND, 0); /* * Initialize the cache to the proper values according with the @@ -2785,9 +3048,10 @@ int dvb_register_frontend(struct dvb_adapter* dvb, } EXPORT_SYMBOL(dvb_register_frontend); -int dvb_unregister_frontend(struct dvb_frontend* fe) +int dvb_unregister_frontend(struct dvb_frontend *fe) { struct dvb_frontend_private *fepriv = fe->frontend_priv; + dev_dbg(fe->dvb->device, "%s:\n", __func__); mutex_lock(&frontend_mutex); @@ -2812,12 +3076,11 @@ static void dvb_frontend_invoke_release(struct dvb_frontend *fe, } } -void dvb_frontend_detach(struct dvb_frontend* fe) +void dvb_frontend_detach(struct dvb_frontend *fe) { dvb_frontend_invoke_release(fe, fe->ops.release_sec); dvb_frontend_invoke_release(fe, fe->ops.tuner_ops.release); dvb_frontend_invoke_release(fe, fe->ops.analog_ops.release); - dvb_frontend_invoke_release(fe, fe->ops.detach); dvb_frontend_put(fe); } EXPORT_SYMBOL(dvb_frontend_detach); diff --git a/dvb-core/dvb_math.c b/dvb-core/dvb_math.c index a2e1810..dc90564 100644 --- a/dvb-core/dvb_math.c +++ b/dvb-core/dvb_math.c @@ -19,7 +19,7 @@ #include #include #include -#include "dvb_math.h" +#include static const unsigned short logtable[256] = { 0x0000, 0x0171, 0x02e0, 0x044e, 0x05ba, 0x0725, 0x088e, 0x09f7, diff --git a/dvb-core/dvb_net.c b/dvb-core/dvb_net.c index dbbc2a3..70a2a5b 100644 --- a/dvb-core/dvb_net.c +++ b/dvb-core/dvb_net.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0-or-later /* * dvb_net.c * @@ -13,18 +14,6 @@ * and Wolfram Stering * * ULE Decaps according to RFC 4326. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * To obtain the license, point your browser to - * http://www.gnu.org/copyleft/gpl.html */ /* @@ -38,7 +27,7 @@ * Competence Center for Advanced Satellite Communications. * Bugfixes and robustness improvements. * Filtering on dest MAC addresses, if present (D-Bit = 0) - * ULE_DEBUG compile-time option. + * DVB_ULE_DEBUG compile-time option. * Apr 2006: cp v3: Bugfixes and compliency with RFC 4326 (ULE) by * Christian Praehauser , * Paris Lodron University of Salzburg. @@ -69,8 +58,8 @@ #include #include -#include "dvb_demux.h" -#include "dvb_net.h" +#include +#include static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt ) { @@ -83,15 +72,20 @@ static inline __u32 iov_crc32( __u32 c, struct kvec *iov, unsigned int cnt ) #define DVB_NET_MULTICAST_MAX 10 -#undef ULE_DEBUG +#undef DVB_ULE_DEBUG -#ifdef ULE_DEBUG +#ifdef DVB_ULE_DEBUG +/* + * The code inside DVB_ULE_DEBUG keeps a history of the + * last 100 TS cells processed. + */ +static unsigned char ule_hist[100*TS_SZ] = { 0 }; +static unsigned char *ule_where = ule_hist, ule_dump; static void hexdump(const unsigned char *buf, unsigned short len) { print_hex_dump_debug("", DUMP_PREFIX_OFFSET, 16, 1, buf, len, true); } - #endif struct dvb_net_priv { @@ -130,7 +124,7 @@ struct dvb_net_priv { }; -/** +/* * Determine the packet's protocol ID. The rule here is that we * assume 802.3 if the type field is short enough to be a length. * This is normal practice and works for any 'now in use' protocol. @@ -160,7 +154,7 @@ static __be16 dvb_net_eth_type_trans(struct sk_buff *skb, rawp = skb->data; - /** + /* * This is a magic hack to spot IPX packets. Older Novell breaks * the protocol design and runs IPX over 802.3 without an 802.2 LLC * layer. We look for FFFF which isn't a used 802.2 SSAP/DSAP. This @@ -169,7 +163,7 @@ static __be16 dvb_net_eth_type_trans(struct sk_buff *skb, if (*(unsigned short *)rawp == 0xFFFF) return htons(ETH_P_802_3); - /** + /* * Real 802.2 LLC */ return htons(ETH_P_802_2); @@ -220,7 +214,8 @@ static int ule_exthdr_padding(struct dvb_net_priv *p) return 0; } -/** Handle ULE extension headers. +/* + * Handle ULE extension headers. * Function is called after a successful CRC32 verification of an ULE SNDU to complete its decoding. * Returns: >= 0: nr. of bytes consumed by next extension header * -1: Mandatory extension header that is not recognized or TEST SNDU; discard. @@ -284,11 +279,9 @@ static int handle_ule_extensions( struct dvb_net_priv *p ) if (l < 0) return l; /* Stop extension header processing and discard SNDU. */ total_ext_len += l; -#ifdef ULE_DEBUG pr_debug("ule_next_hdr=%p, ule_sndu_type=%i, l=%i, total_ext_len=%i\n", p->ule_next_hdr, (int)p->ule_sndu_type, l, total_ext_len); -#endif } while (p->ule_sndu_type < ETH_P_802_3_MIN); @@ -296,7 +289,7 @@ static int handle_ule_extensions( struct dvb_net_priv *p ) } -/** Prepare for a new ULE SNDU: reset the decoder state. */ +/* Prepare for a new ULE SNDU: reset the decoder state. */ static inline void reset_ule( struct dvb_net_priv *p ) { p->ule_skb = NULL; @@ -309,7 +302,7 @@ static inline void reset_ule( struct dvb_net_priv *p ) p->ule_bridged = 0; } -/** +/* * Decode ULE SNDUs according to draft-ietf-ipdvb-ule-03.txt from a sequence of * TS cells of a single PID. */ @@ -324,29 +317,21 @@ struct dvb_net_ule_handle { const u8 *ts, *ts_end, *from_where; u8 ts_remain, how_much, new_ts; bool error; -#ifdef ULE_DEBUG - /* - * The code inside ULE_DEBUG keeps a history of the - * last 100 TS cells processed. - */ - static unsigned char ule_hist[100*TS_SZ]; - static unsigned char *ule_where = ule_hist, ule_dump; -#endif }; static int dvb_net_ule_new_ts_cell(struct dvb_net_ule_handle *h) { /* We are about to process a new TS cell. */ -#ifdef ULE_DEBUG - if (h->ule_where >= &h->ule_hist[100*TS_SZ]) - h->ule_where = h->ule_hist; - memcpy(h->ule_where, h->ts, TS_SZ); - if (h->ule_dump) { - hexdump(h->ule_where, TS_SZ); - h->ule_dump = 0; +#ifdef DVB_ULE_DEBUG + if (ule_where >= &ule_hist[100*TS_SZ]) + ule_where = ule_hist; + memcpy(ule_where, h->ts, TS_SZ); + if (ule_dump) { + hexdump(ule_where, TS_SZ); + ule_dump = 0; } - h->ule_where += TS_SZ; + ule_where += TS_SZ; #endif /* @@ -664,6 +649,7 @@ static int dvb_net_ule_should_drop(struct dvb_net_ule_handle *h) static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h, + struct kvec iov[3], u32 ule_crc, u32 expected_crc) { u8 dest_addr[ETH_ALEN]; @@ -676,22 +662,22 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h, h->ts_remain > 2 ? *(unsigned short *)h->from_where : 0); - #ifdef ULE_DEBUG + #ifdef DVB_ULE_DEBUG hexdump(iov[0].iov_base, iov[0].iov_len); hexdump(iov[1].iov_base, iov[1].iov_len); hexdump(iov[2].iov_base, iov[2].iov_len); - if (h->ule_where == h->ule_hist) { - hexdump(&h->ule_hist[98*TS_SZ], TS_SZ); - hexdump(&h->ule_hist[99*TS_SZ], TS_SZ); - } else if (h->ule_where == &h->ule_hist[TS_SZ]) { - hexdump(&h->ule_hist[99*TS_SZ], TS_SZ); - hexdump(h->ule_hist, TS_SZ); + if (ule_where == ule_hist) { + hexdump(&ule_hist[98*TS_SZ], TS_SZ); + hexdump(&ule_hist[99*TS_SZ], TS_SZ); + } else if (ule_where == &ule_hist[TS_SZ]) { + hexdump(&ule_hist[99*TS_SZ], TS_SZ); + hexdump(ule_hist, TS_SZ); } else { - hexdump(h->ule_where - TS_SZ - TS_SZ, TS_SZ); - hexdump(h->ule_where - TS_SZ, TS_SZ); + hexdump(ule_where - TS_SZ - TS_SZ, TS_SZ); + hexdump(ule_where - TS_SZ, TS_SZ); } - h->ule_dump = 1; + ule_dump = 1; #endif h->dev->stats.rx_errors++; @@ -709,11 +695,9 @@ static void dvb_net_ule_check_crc(struct dvb_net_ule_handle *h, if (!h->priv->ule_dbit) { if (dvb_net_ule_should_drop(h)) { -#ifdef ULE_DEBUG netdev_dbg(h->dev, "Dropping SNDU: MAC destination address does not match: dest addr: %pM, h->dev addr: %pM\n", h->priv->ule_skb->data, h->dev->dev_addr); -#endif dev_kfree_skb(h->priv->ule_skb); return; } @@ -784,6 +768,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) struct dvb_net_ule_handle h = { .dev = dev, .priv = netdev_priv(dev), + .ethh = NULL, .buf = buf, .buf_len = buf_len, .skipped = 0L, @@ -793,11 +778,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) .ts_remain = 0, .how_much = 0, .new_ts = 1, - .ethh = NULL, .error = false, -#ifdef ULE_DEBUG - .ule_where = ule_hist, -#endif }; /* @@ -869,7 +850,7 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) *(tail - 2) << 8 | *(tail - 1); - dvb_net_ule_check_crc(&h, ule_crc, expected_crc); + dvb_net_ule_check_crc(&h, iov, ule_crc, expected_crc); /* Prepare for next SNDU. */ reset_ule(h.priv); @@ -902,7 +883,8 @@ static void dvb_net_ule(struct net_device *dev, const u8 *buf, size_t buf_len) static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, - struct dmx_ts_feed *feed) + struct dmx_ts_feed *feed, + u32 *buffer_flags) { struct net_device *dev = feed->priv; @@ -1010,12 +992,12 @@ static void dvb_net_sec(struct net_device *dev, } static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, - const u8 *buffer2, size_t buffer2_len, - struct dmx_section_filter *filter) + const u8 *buffer2, size_t buffer2_len, + struct dmx_section_filter *filter, u32 *buffer_flags) { struct net_device *dev = filter->priv; - /** + /* * we rely on the DVB API definition where exactly one complete * section is delivered in buffer1 */ @@ -1023,7 +1005,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len, return 0; } -static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev) +static netdev_tx_t dvb_net_tx(struct sk_buff *skb, struct net_device *dev) { dev_kfree_skb(skb); return NETDEV_TX_OK; diff --git a/dvb-core/dvb_ringbuffer.c b/dvb-core/dvb_ringbuffer.c index 6406e6e..42f39af 100644 --- a/dvb-core/dvb_ringbuffer.c +++ b/dvb-core/dvb_ringbuffer.c @@ -34,7 +34,7 @@ #include #endif -#include "dvb_ringbuffer.h" +#include #define PKT_READY 0 #define PKT_DISPOSED 1 @@ -63,7 +63,7 @@ int dvb_ringbuffer_empty(struct dvb_ringbuffer *rbuf) * this pairs with smp_store_release() in dvb_ringbuffer_write(), * dvb_ringbuffer_write_user(), or dvb_ringbuffer_reset() * - * for memory barriers also see Documentation/circular-buffers.txt + * for memory barriers also see Documentation/core-api/circular-buffers.txt */ return (rbuf->pread == smp_load_acquire(&rbuf->pwrite)); #endif diff --git a/dvb-core/dvbdev.c b/dvb-core/dvbdev.c index 6d63578..d4bf829 100644 --- a/dvb-core/dvbdev.c +++ b/dvb-core/dvbdev.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -31,7 +32,7 @@ #include #include #include -#include "dvbdev.h" +#include #if (LINUX_VERSION_CODE > KERNEL_VERSION(4,0,0)) /* Due to enum tuner_pad_index */ @@ -54,8 +55,19 @@ static LIST_HEAD(dvb_adapter_list); static DEFINE_MUTEX(dvbdev_register_lock); static const char * const dnames[] = { - "video", "audio", "sec", "frontend", "demux", "dvr", "ca", - "net", "osd", "ci", "mod", "ns", "nsd" + [DVB_DEVICE_VIDEO] = "video", + [DVB_DEVICE_AUDIO] = "audio", + [DVB_DEVICE_SEC] = "sec", + [DVB_DEVICE_FRONTEND] = "frontend", + [DVB_DEVICE_DEMUX] = "demux", + [DVB_DEVICE_DVR] = "dvr", + [DVB_DEVICE_CA] = "ca", + [DVB_DEVICE_NET] = "net", + [DVB_DEVICE_OSD] = "osd", + [DVB_DEVICE_CI] = "ci", + [DVB_DEVICE_MOD] = "mod", + [DVB_DEVICE_NS] = "ns", + [DVB_DEVICE_NSD] = "nsd", }; #ifdef CONFIG_DVB_DYNAMIC_MINORS @@ -63,7 +75,22 @@ static const char * const dnames[] = { #define DVB_MAX_IDS MAX_DVB_MINORS #else #define DVB_MAX_IDS 4 -#define nums2minor(num, type, id) ((num << 6) | (id << 4) | type) + +static const u8 minor_type[] = { + [DVB_DEVICE_VIDEO] = 0, + [DVB_DEVICE_AUDIO] = 1, + [DVB_DEVICE_SEC] = 2, + [DVB_DEVICE_FRONTEND] = 3, + [DVB_DEVICE_DEMUX] = 4, + [DVB_DEVICE_DVR] = 5, + [DVB_DEVICE_CA] = 6, + [DVB_DEVICE_NET] = 7, + [DVB_DEVICE_OSD] = 8, +}; + +#define nums2minor(num, type, id) \ + (((num) << 6) | ((id) << 4) | minor_type[type]) + #define MAX_DVB_MINORS (DVB_MAX_ADAPTERS*64) #endif @@ -319,8 +346,10 @@ static int dvb_create_media_entity(struct dvb_device *dvbdev, if (npads) { dvbdev->pads = kcalloc(npads, sizeof(*dvbdev->pads), GFP_KERNEL); - if (!dvbdev->pads) + if (!dvbdev->pads){ + kfree(dvbdev->entity); return -ENOMEM; + } } switch (type) { @@ -420,8 +449,10 @@ static int dvb_register_media_device(struct dvb_device *dvbdev, if (!dvbdev->entity) return 0; - link = media_create_intf_link(dvbdev->entity, &dvbdev->intf_devnode->intf, - MEDIA_LNK_FL_ENABLED); + link = media_create_intf_link(dvbdev->entity, + &dvbdev->intf_devnode->intf, + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); if (!link) return -ENOMEM; #endif @@ -429,8 +460,8 @@ static int dvb_register_media_device(struct dvb_device *dvbdev, } int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, - const struct dvb_device *template, void *priv, int type, - int demux_sink_pads) + const struct dvb_device *template, void *priv, + enum dvb_device_type type, int demux_sink_pads) { struct dvb_device *dvbdev; struct file_operations *dvbdevfops; @@ -454,7 +485,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, return -ENOMEM; } - dvbdevfops = kzalloc(sizeof(struct file_operations), GFP_KERNEL); + dvbdevfops = kmemdup(template->fops, sizeof(*dvbdevfops), GFP_KERNEL); if (!dvbdevfops){ kfree (dvbdev); @@ -470,7 +501,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, dvbdev->fops = dvbdevfops; init_waitqueue_head (&dvbdev->wait_queue); - memcpy(dvbdevfops, template->fops, sizeof(struct file_operations)); dvbdevfops->owner = adap->module; list_add_tail (&dvbdev->list_head, &adap->device_list); @@ -504,7 +534,6 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, dvb_media_device_free(dvbdev); kfree(dvbdevfops); kfree(dvbdev); - up_write(&minor_rwsem); mutex_unlock(&dvbdev_register_lock); return ret; } @@ -579,7 +608,8 @@ static int dvb_create_io_intf_links(struct dvb_adapter *adap, if (strncmp(entity->name, name, strlen(name))) continue; link = media_create_intf_link(entity, intf, - MEDIA_LNK_FL_ENABLED); + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); if (!link) return -ENOMEM; } @@ -598,8 +628,7 @@ int dvb_create_media_graph(struct dvb_adapter *adap, unsigned demux_pad = 0; unsigned dvr_pad = 0; unsigned ntuner = 0, ndemod = 0; - u16 source_pad = 0; - int ret; + int ret, pad_source, pad_sink; static const char *connector_name = "Television"; if (!mdev) @@ -660,17 +689,6 @@ int dvb_create_media_graph(struct dvb_adapter *adap, return ret; if (!ntuner) { - -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0)) - if ((ret = media_get_pad_index(tuner, true, - PAD_SIGNAL_ANALOG)) < 0) - return ret; - source_pad = (u16) ret; - ret = 0; -#else - source_pad = TUNER_PAD_RF_INPUT; -#endif - ret = media_create_pad_links(mdev, MEDIA_ENT_F_CONN_RF, conn, 0, @@ -679,32 +697,40 @@ int dvb_create_media_graph(struct dvb_adapter *adap, MEDIA_LNK_FL_ENABLED, false); } else { +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0)) + pad_sink = media_get_pad_index(tuner, true, + PAD_SIGNAL_ANALOG); + if (pad_sink < 0) + return -EINVAL; ret = media_create_pad_links(mdev, MEDIA_ENT_F_CONN_RF, conn, 0, MEDIA_ENT_F_TUNER, - tuner, source_pad, + tuner, pad_sink, MEDIA_LNK_FL_ENABLED, false); +#else + pad_sink = TUNER_PAD_RF_INPUT; +#endif } if (ret) return ret; } if (ntuner && ndemod) { - #if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,2,0)) - if ((ret = media_get_pad_index(tuner, true, PAD_SIGNAL_ANALOG)) < 0) - return ret; - source_pad = (u16) ret; - ret = 0; + /* NOTE: first found tuner source pad presumed correct */ + pad_source = media_get_pad_index(tuner, false, + PAD_SIGNAL_ANALOG); + if (pad_source < 0) + return -EINVAL; #else - source_pad = TUNER_PAD_OUTPUT; + pad_source = TUNER_PAD_OUTPUT; #endif ret = media_create_pad_links(mdev, MEDIA_ENT_F_TUNER, - tuner, source_pad, + tuner, pad_source, MEDIA_ENT_F_DTV_DEMOD, demod, 0, MEDIA_LNK_FL_ENABLED, false); @@ -757,14 +783,16 @@ int dvb_create_media_graph(struct dvb_adapter *adap, media_device_for_each_intf(intf, mdev) { if (intf->type == MEDIA_INTF_T_DVB_CA && ca) { link = media_create_intf_link(ca, intf, - MEDIA_LNK_FL_ENABLED); + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); if (!link) return -ENOMEM; } if (intf->type == MEDIA_INTF_T_DVB_FE && tuner) { link = media_create_intf_link(tuner, intf, - MEDIA_LNK_FL_ENABLED); + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); if (!link) return -ENOMEM; } @@ -776,7 +804,8 @@ int dvb_create_media_graph(struct dvb_adapter *adap, */ if (intf->type == MEDIA_INTF_T_DVB_DVR && demux) { link = media_create_intf_link(demux, intf, - MEDIA_LNK_FL_ENABLED); + MEDIA_LNK_FL_ENABLED | + MEDIA_LNK_FL_IMMUTABLE); if (!link) return -ENOMEM; } @@ -862,6 +891,10 @@ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, adap->mfe_dvbdev = NULL; mutex_init (&adap->mfe_lock); +#ifdef CONFIG_MEDIA_CONTROLLER_DVB + mutex_init(&adap->mdev_lock); +#endif + list_add_tail (&adap->list_head, &dvb_adapter_list); mutex_unlock(&dvbdev_register_lock); @@ -882,7 +915,7 @@ EXPORT_SYMBOL(dvb_unregister_adapter); /* if the miracle happens and "generic_usercopy()" is included into the kernel, then this can vanish. please don't make the mistake and - define this as video_usercopy(). this will introduce a dependecy + define this as video_usercopy(). this will introduce a dependency to the v4l "videodev.o" module, which is unnecessary for some cards (ie. the budget dvb-cards don't need the v4l module...) */ int dvb_usercopy(struct file *file, @@ -946,6 +979,57 @@ out: } EXPORT_SYMBOL(dvb_usercopy); +#if IS_ENABLED(CONFIG_I2C) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)) +struct i2c_client *dvb_module_probe(const char *module_name, + const char *name, + struct i2c_adapter *adap, + unsigned char addr, + void *platform_data) +{ + struct i2c_client *client; + struct i2c_board_info *board_info; + + board_info = kzalloc(sizeof(*board_info), GFP_KERNEL); + if (!board_info) + return NULL; + + if (name) + strscpy(board_info->type, name, I2C_NAME_SIZE); + else + strscpy(board_info->type, module_name, I2C_NAME_SIZE); + + board_info->addr = addr; + board_info->platform_data = platform_data; + request_module(module_name); + client = i2c_new_client_device(adap, board_info); + if (!i2c_client_has_driver(client)) { + kfree(board_info); + return NULL; + } + + if (!try_module_get(client->dev.driver->owner)) { + i2c_unregister_device(client); + client = NULL; + } + + kfree(board_info); + return client; +} +EXPORT_SYMBOL_GPL(dvb_module_probe); + +void dvb_module_release(struct i2c_client *client) +{ + if (!client) + return; + + module_put(client->dev.driver->owner); + i2c_unregister_device(client); +} +EXPORT_SYMBOL_GPL(dvb_module_release); +#endif +#endif + static int dvb_uevent(struct device *dev, struct kobj_uevent_env *env) { struct dvb_device *dvbdev = dev_get_drvdata(dev); diff --git a/frontends/Makefile b/frontends/Makefile index 49b8417..a6de4a5 100644 --- a/frontends/Makefile +++ b/frontends/Makefile @@ -16,7 +16,6 @@ EXTRA_CFLAGS += -DCONFIG_DVB_LNBH25 EXTRA_CFLAGS += -DCONFIG_DVB_MXL5XX EXTRA_CFLAGS += -DCONFIG_DVB_CXD2099 EXTRA_CFLAGS += -DDBVALS -NOSTDINC_FLAGS += -I$(KBUILD_EXTMOD)/include -I$(KBUILD_EXTMOD)/dvb-core drxk-objs := drxk_hard.o obj-$(CONFIG_DVB_DRXK) += drxk.o diff --git a/frontends/cxd2099.h b/frontends/cxd2099.h index f4b29b1..1235d5e 100644 --- a/frontends/cxd2099.h +++ b/frontends/cxd2099.h @@ -25,7 +25,7 @@ #ifndef _CXD2099_H_ #define _CXD2099_H_ -#include +#include struct cxd2099_cfg { u32 bitrate; diff --git a/frontends/cxd2843.c b/frontends/cxd2843.c index c0d10f2..d6f0646 100644 --- a/frontends/cxd2843.c +++ b/frontends/cxd2843.c @@ -35,8 +35,8 @@ #include #include -#include "dvb_frontend.h" -#include "dvb_math.h" +#include +#include #include "cxd2843.h" #define Log10x100(x) ((s32)(((((u64) intlog2(x) * 0x1e1a5e2e) >> 47 ) + 1) >> 1)) @@ -105,8 +105,12 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) static int writeregs(struct cxd_state *state, u8 adr, u8 reg, u8 *regd, u16 len) { - u8 data[len + 1]; + u8 data[16]; + if (len >= 15) { + pr_err("cxd2843: writeregs length %u too large\n", len); + return -1; + } data[0] = reg; memcpy(data + 1, regd, len); return i2c_write(state->i2c, adr, data, len + 1); @@ -2240,7 +2244,7 @@ static enum dvbfe_search search(struct dvb_frontend *fe) return DVBFE_ALGO_SEARCH_AGAIN; } -static int get_algo(struct dvb_frontend *fe) +static enum dvbfe_algo get_algo(struct dvb_frontend *fe) { return DVBFE_ALGO_HW; } @@ -2489,9 +2493,9 @@ static struct dvb_frontend_ops common_ops_2854 = { .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2, SYS_ISDBT }, .info = { .name = "CXD2854 DVB-C/C2 DVB-T/T2 ISDB-T", - .frequency_stepsize = 166667, /* DVB-T only */ - .frequency_min = 47000000, /* DVB-T: 47125000 */ - .frequency_max = 865000000, /* DVB-C: 862000000 */ + .frequency_stepsize_hz = 166667, /* DVB-T only */ + .frequency_min_hz = 47000000, /* DVB-T: 47125000 */ + .frequency_max_hz = 865000000, /* DVB-C: 862000000 */ .symbol_rate_min = 870000, .symbol_rate_max = 11700000, .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | @@ -2523,9 +2527,9 @@ static struct dvb_frontend_ops common_ops_2843 = { .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2, SYS_DVBC2 }, .info = { .name = "CXD2843 DVB-C/C2 DVB-T/T2", - .frequency_stepsize = 166667, /* DVB-T only */ - .frequency_min = 47000000, /* DVB-T: 47125000 */ - .frequency_max = 865000000, /* DVB-C: 862000000 */ + .frequency_stepsize_hz = 166667, /* DVB-T only */ + .frequency_min_hz = 47000000, /* DVB-T: 47125000 */ + .frequency_max_hz = 865000000, /* DVB-C: 862000000 */ .symbol_rate_min = 870000, .symbol_rate_max = 11700000, .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | @@ -2562,9 +2566,9 @@ static struct dvb_frontend_ops common_ops_2837 = { .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT, SYS_DVBT2 }, .info = { .name = "CXD2837 DVB-C DVB-T/T2", - .frequency_stepsize = 166667, /* DVB-T only */ - .frequency_min = 47000000, /* DVB-T: 47125000 */ - .frequency_max = 865000000, /* DVB-C: 862000000 */ + .frequency_stepsize_hz = 166667, /* DVB-T only */ + .frequency_min_hz = 47000000, /* DVB-T: 47125000 */ + .frequency_max_hz = 865000000, /* DVB-C: 862000000 */ .symbol_rate_min = 870000, .symbol_rate_max = 11700000, .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_32 | @@ -2601,9 +2605,9 @@ static struct dvb_frontend_ops common_ops_2838 = { .delsys = { SYS_ISDBT }, .info = { .name = "CXD2838 ISDB-T", - .frequency_stepsize = 166667, - .frequency_min = 47000000, - .frequency_max = 865000000, + .frequency_stepsize_hz = 166667, + .frequency_min_hz = 47000000, + .frequency_max_hz = 865000000, .symbol_rate_min = 870000, .symbol_rate_max = 11700000, .caps = FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO | diff --git a/frontends/drxk_hard.c b/frontends/drxk_hard.c index 3ef782e..456e382 100644 --- a/frontends/drxk_hard.c +++ b/frontends/drxk_hard.c @@ -31,7 +31,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "drxk.h" #include "drxk_hard.h" @@ -2804,10 +2804,12 @@ static int DVBTScCommand(struct drxk_state *state, case OFDM_SC_RA_RAM_CMD_PROGRAM_PARAM: status = Write16_0(state, OFDM_SC_RA_RAM_PARAM1__A, param1); /* All commands using 1 parameters */ + /* fall through */ case OFDM_SC_RA_RAM_CMD_SET_ECHO_TIMING: case OFDM_SC_RA_RAM_CMD_USER_IO: status = Write16_0(state, OFDM_SC_RA_RAM_PARAM0__A, param0); /* All commands using 0 parameters */ + /* fall through */ case OFDM_SC_RA_RAM_CMD_GET_OP_PARAM: case OFDM_SC_RA_RAM_CMD_NULL: /* Write command */ @@ -3215,7 +3217,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF case TRANSMISSION_MODE_AUTO: default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_MODE__M; - /* fall through , try first guess DRX_FFTMODE_8K */ + /* try first guess DRX_FFTMODE_8K */ + /* fall through */ case TRANSMISSION_MODE_8K: transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_MODE_8K; break; @@ -3233,7 +3236,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF default: case GUARD_INTERVAL_AUTO: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_GUARD__M; - /* fall through , try first guess DRX_GUARD_1DIV4 */ + /* try first guess DRX_GUARD_1DIV4 */ + /* fall through */ case GUARD_INTERVAL_1_4: transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_GUARD_4; break; @@ -3258,9 +3262,10 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF case HIERARCHY_NONE: default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_HIER__M; - /* fall through , try first guess SC_RA_RAM_OP_PARAM_HIER_NO */ + /* try first guess SC_RA_RAM_OP_PARAM_HIER_NO */ // transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_NO; //break; + /* fall through */ case HIERARCHY_1: transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_HIER_A1; break; @@ -3282,7 +3287,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF case QAM_AUTO: default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_CONST__M; - /* fall through , try first guess DRX_CONSTELLATION_QAM64 */ + /* try first guess DRX_CONSTELLATION_QAM64 */ + /* fall through */ case QAM_64: transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_CONST_QAM64; break; @@ -3325,7 +3331,8 @@ static int SetDVBT (struct drxk_state *state,u16 IntermediateFreqkHz, s32 tunerF case FEC_AUTO: default: operationMode |= OFDM_SC_RA_RAM_OP_AUTO_RATE__M; - /* fall through , try first guess DRX_CODERATE_2DIV3 */ + /* try first guess DRX_CODERATE_2DIV3 */ + /* fall through */ case FEC_2_3 : transmissionParams |= OFDM_SC_RA_RAM_OP_PARAM_RATE_2_3; break; @@ -4994,12 +5001,12 @@ static int drxk_t_get_frontend(struct dvb_frontend *fe, struct dtv_frontend_prop } static struct dvb_frontend_ops drxk_c_ops = { + .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBC_ANNEX_B, SYS_DVBC_ANNEX_C }, .info = { .name = "DRXK DVB-C", - .type = FE_QAM, - .frequency_stepsize = 62500, - .frequency_min = 47000000, - .frequency_max = 862000000, + .frequency_stepsize_hz = 62500, + .frequency_min_hz = 47000000, + .frequency_max_hz = 862000000, .symbol_rate_min = 870000, .symbol_rate_max = 11700000, .caps = FE_CAN_QAM_16 | FE_CAN_QAM_32 | FE_CAN_QAM_64 | @@ -5022,13 +5029,13 @@ static struct dvb_frontend_ops drxk_c_ops = { }; static struct dvb_frontend_ops drxk_t_ops = { + .delsys = { SYS_DVBT }, .info = { .name = "DRXK DVB-T", - .type = FE_OFDM, - .frequency_min = 47125000, - .frequency_max = 865000000, - .frequency_stepsize = 166667, - .frequency_tolerance = 0, + .frequency_min_hz = 47125000, + .frequency_max_hz = 865000000, + .frequency_stepsize_hz = 166667, + .frequency_tolerance_hz = 0, .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO | diff --git a/frontends/lnbh25.c b/frontends/lnbh25.c index 9e904c5..823ac15 100644 --- a/frontends/lnbh25.c +++ b/frontends/lnbh25.c @@ -30,7 +30,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "lnbh25.h" struct lnbh25 { diff --git a/frontends/lnbp21.c b/frontends/lnbp21.c index f70b1cb..61e4269 100644 --- a/frontends/lnbp21.c +++ b/frontends/lnbp21.c @@ -32,7 +32,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "lnbp21.h" #include "lnbh24.h" diff --git a/frontends/mxl5xx.c b/frontends/mxl5xx.c index 078f33d..6f7308b 100644 --- a/frontends/mxl5xx.c +++ b/frontends/mxl5xx.c @@ -41,7 +41,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "mxl5xx.h" #include "mxl5xx_regs.h" #include "mxl5xx_defs.h" @@ -392,7 +392,7 @@ static void release(struct dvb_frontend *fe) kfree(state); } -static int get_algo(struct dvb_frontend *fe) +static enum dvbfe_algo get_algo(struct dvb_frontend *fe) { return DVBFE_ALGO_HW; } @@ -786,6 +786,7 @@ static int get_frontend(struct dvb_frontend *fe, struct dtv_frontend_properties default: break; } + /* fallthrough */ case SYS_DVBS: switch ((MXL_HYDRA_MODULATION_E) regData[DMD_MODULATION_SCHEME_ADDR]) { @@ -833,10 +834,10 @@ static struct dvb_frontend_ops mxl_ops = { .xbar = { 4, 0, 8 }, /* tuner_max, demod id, demod_max */ .info = { .name = "MXL5XX", - .frequency_min = 300000, - .frequency_max = 2350000, - .frequency_stepsize = 0, - .frequency_tolerance = 0, + .frequency_min_hz = 300000000, + .frequency_max_hz = 2350000000, + .frequency_stepsize_hz = 0, + .frequency_tolerance_hz = 0, .symbol_rate_min = 1000000, .symbol_rate_max = 45000000, .caps = FE_CAN_INVERSION_AUTO | diff --git a/frontends/stv0367dd.c b/frontends/stv0367dd.c index 3f4f247..d127545 100644 --- a/frontends/stv0367dd.c +++ b/frontends/stv0367dd.c @@ -31,7 +31,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "stv0367dd.h" #include "stv0367dd_regs.h" @@ -2074,9 +2074,9 @@ static struct dvb_frontend_ops common_ops = { .delsys = { SYS_DVBC_ANNEX_A, SYS_DVBT }, .info = { .name = "STV0367 DVB-C DVB-T", - .frequency_stepsize = 166667, /* DVB-T only */ - .frequency_min = 47000000, /* DVB-T: 47125000 */ - .frequency_max = 865000000, /* DVB-C: 862000000 */ + .frequency_stepsize_hz = 166667, /* DVB-T only */ + .frequency_min_hz = 47000000, /* DVB-T: 47125000 */ + .frequency_max_hz = 865000000, /* DVB-C: 862000000 */ .symbol_rate_min = 870000, .symbol_rate_max = 11700000, .caps = /* DVB-C */ diff --git a/frontends/stv090x.c b/frontends/stv090x.c index f818902..6ec0ecf 100644 --- a/frontends/stv090x.c +++ b/frontends/stv090x.c @@ -28,7 +28,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "stv6110x.h" /* for demodulator internal modes */ @@ -5142,10 +5142,10 @@ static struct dvb_frontend_ops stv090x_ops = { #ifdef USE_API3 .type = FE_QPSK, #endif - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 0, - .frequency_tolerance = 0, + .frequency_min_hz = 950000000, + .frequency_max_hz = 2150000000, + .frequency_stepsize_hz = 0, + .frequency_tolerance_hz = 0, .symbol_rate_min = 1000000, .symbol_rate_max = 45000000, .caps = FE_CAN_INVERSION_AUTO | diff --git a/frontends/stv090x_priv.h b/frontends/stv090x_priv.h index 8c1953f..97a9efe 100644 --- a/frontends/stv090x_priv.h +++ b/frontends/stv090x_priv.h @@ -22,7 +22,7 @@ #ifndef __STV090x_PRIV_H #define __STV090x_PRIV_H -#include "dvb_frontend.h" +#include #define FE_ERROR 0 #define FE_NOTICE 1 diff --git a/frontends/stv0910.c b/frontends/stv0910.c index ab1b4c4..b289ef7 100644 --- a/frontends/stv0910.c +++ b/frontends/stv0910.c @@ -31,7 +31,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "stv0910.h" #include "stv0910_regs.h" @@ -1581,7 +1581,7 @@ static int tune(struct dvb_frontend *fe, bool re_tune, return 0; } -static int get_algo(struct dvb_frontend *fe) +static enum dvbfe_algo get_algo(struct dvb_frontend *fe) { return DVBFE_ALGO_HW; } @@ -1801,10 +1801,10 @@ static struct dvb_frontend_ops stv0910_ops = { .delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS }, .info = { .name = "STV0910", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_stepsize = 0, - .frequency_tolerance = 0, + .frequency_min_hz = 950000000, + .frequency_max_hz = 2150000000, + .frequency_stepsize_hz = 0, + .frequency_tolerance_hz = 0, .symbol_rate_min = 100000, .symbol_rate_max = 70000000, .caps = FE_CAN_INVERSION_AUTO | diff --git a/frontends/stv6110x.c b/frontends/stv6110x.c index 66eba38..4469f4a 100644 --- a/frontends/stv6110x.c +++ b/frontends/stv6110x.c @@ -26,7 +26,7 @@ #include #include -#include "dvb_frontend.h" +#include #include "stv6110x_reg.h" #include "stv6110x.h" @@ -345,10 +345,10 @@ static void stv6110x_release(struct dvb_frontend *fe) static const struct dvb_tuner_ops stv6110x_ops = { .info = { - .name = "STV6110(A) Silicon Tuner", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_step = 0, + .name = "STV6110(A) Silicon Tuner", + .frequency_min_hz = 950000000, + .frequency_max_hz = 2150000000, + .frequency_step_hz = 0, }, .release = stv6110x_release }; diff --git a/frontends/stv6111.c b/frontends/stv6111.c index 0689df5..3d10d8a 100644 --- a/frontends/stv6111.c +++ b/frontends/stv6111.c @@ -31,7 +31,7 @@ #include #include -#include "dvb_frontend.h" +#include static inline u32 MulDiv32(u32 a, u32 b, u32 c) { @@ -706,9 +706,9 @@ static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) static struct dvb_tuner_ops tuner_ops = { .info = { .name = "STV6111", - .frequency_min = 950000, - .frequency_max = 2150000, - .frequency_step = 0 + .frequency_min_hz = 950000000, + .frequency_max_hz = 2150000000, + .frequency_step_hz = 0 }, .init = init, .sleep = sleep, diff --git a/frontends/tda18212dd.c b/frontends/tda18212dd.c index 5629e5e..cf43a22 100644 --- a/frontends/tda18212dd.c +++ b/frontends/tda18212dd.c @@ -32,7 +32,7 @@ #include #include -#include "dvb_frontend.h" +#include #ifndef CHK_ERROR #define CHK_ERROR(s) if ((status = s) < 0) break @@ -889,9 +889,9 @@ static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) static struct dvb_tuner_ops tuner_ops = { .info = { .name = "NXP TDA18212", - .frequency_min = 47125000, - .frequency_max = 865000000, - .frequency_step = 62500 + .frequency_min_hz = 47125000, + .frequency_max_hz = 865000000, + .frequency_step_hz = 62500 }, .init = init, .sleep = sleep, diff --git a/frontends/tda18271c2dd.c b/frontends/tda18271c2dd.c index 4ea9a71..39fd090 100644 --- a/frontends/tda18271c2dd.c +++ b/frontends/tda18271c2dd.c @@ -32,7 +32,7 @@ #include #include -#include "dvb_frontend.h" +#include struct SStandardParam { s32 m_IFFrequency; @@ -1183,6 +1183,7 @@ static int set_params(struct dvb_frontend *fe, switch (delsys) { case SYS_DVBT: + /* fallthrough */ case SYS_DVBT2: switch (bw) { case 6000000: @@ -1197,7 +1198,9 @@ static int set_params(struct dvb_frontend *fe, default: return -EINVAL; } + break; case SYS_DVBC_ANNEX_A: + /* fallthrough */ case SYS_DVBC_ANNEX_C: if (bw <= 6000000) Standard = HF_DVBC_6MHZ; @@ -1292,9 +1295,9 @@ static int get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth) static struct dvb_tuner_ops tuner_ops = { .info = { .name = "NXP TDA18271C2D", - .frequency_min = 47125000, - .frequency_max = 865000000, - .frequency_step = 62500 + .frequency_min_hz = 47125000, + .frequency_max_hz = 865000000, + .frequency_step_hz = 62500 }, .init = init, .sleep = sleep, diff --git a/dvb-core/demux.h b/include/linux/media/demux.h similarity index 97% rename from dvb-core/demux.h rename to include/linux/media/demux.h index c4df6ce..bf00a5a 100644 --- a/dvb-core/demux.h +++ b/include/linux/media/demux.h @@ -117,7 +117,7 @@ struct dmx_ts_feed { * specified by @filter_value that will be used on the filter * match logic. * @filter_mode: Contains a 16 bytes (128 bits) filter mode. - * @parent: Pointer to struct dmx_section_feed. + * @parent: Back-pointer to struct dmx_section_feed. * @priv: Pointer to private data of the API client. * * @@ -130,8 +130,9 @@ struct dmx_section_filter { u8 filter_value[DMX_MAX_FILTER_SIZE]; u8 filter_mask[DMX_MAX_FILTER_SIZE]; u8 filter_mode[DMX_MAX_FILTER_SIZE]; - struct dmx_section_feed *parent; /* Back-pointer */ - void *priv; /* Pointer to private data of the API client */ + struct dmx_section_feed *parent; + + void *priv; }; /** @@ -193,6 +194,10 @@ struct dmx_section_feed { * @buffer2: Pointer to the tail of the filtered TS packets, or NULL. * @buffer2_length: Length of the TS data in buffer2. * @source: Indicates which TS feed is the source of the callback. + * @buffer_flags: Address where buffer flags are stored. Those are + * used to report discontinuity users via DVB + * memory mapped API, as defined by + * &enum dmx_buffer_flags. * * This function callback prototype, provided by the client of the demux API, * is called from the demux code. The function is only called when filtering @@ -245,7 +250,8 @@ typedef int (*dmx_ts_cb)(const u8 *buffer1, size_t buffer1_length, const u8 *buffer2, size_t buffer2_length, - struct dmx_ts_feed *source); + struct dmx_ts_feed *source, + u32 *buffer_flags); /** * typedef dmx_section_cb - DVB demux TS filter callback function prototype @@ -261,6 +267,10 @@ typedef int (*dmx_ts_cb)(const u8 *buffer1, * including headers and CRC. * @source: Indicates which section feed is the source of the * callback. + * @buffer_flags: Address where buffer flags are stored. Those are + * used to report discontinuity users via DVB + * memory mapped API, as defined by + * &enum dmx_buffer_flags. * * This function callback prototype, provided by the client of the demux API, * is called from the demux code. The function is only called when @@ -286,7 +296,8 @@ typedef int (*dmx_section_cb)(const u8 *buffer1, size_t buffer1_len, const u8 *buffer2, size_t buffer2_len, - struct dmx_section_filter *source); + struct dmx_section_filter *source, + u32 *buffer_flags); /* * DVB Front-End diff --git a/include/linux/media/dmxdev.h b/include/linux/media/dmxdev.h new file mode 100644 index 0000000..729e36e --- /dev/null +++ b/include/linux/media/dmxdev.h @@ -0,0 +1,220 @@ +/* + * dmxdev.h + * + * Copyright (C) 2000 Ralph Metzler & Marcus Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _DMXDEV_H_ +#define _DMXDEV_H_ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#ifdef CONFIG_DVB_MMAP +#include +#endif + +/** + * enum dmxdev_type - type of demux filter type. + * + * @DMXDEV_TYPE_NONE: no filter set. + * @DMXDEV_TYPE_SEC: section filter. + * @DMXDEV_TYPE_PES: Program Elementary Stream (PES) filter. + */ +enum dmxdev_type { + DMXDEV_TYPE_NONE, + DMXDEV_TYPE_SEC, + DMXDEV_TYPE_PES, +}; + +/** + * enum dmxdev_state - state machine for the dmxdev. + * + * @DMXDEV_STATE_FREE: indicates that the filter is freed. + * @DMXDEV_STATE_ALLOCATED: indicates that the filter was allocated + * to be used. + * @DMXDEV_STATE_SET: indicates that the filter parameters are set. + * @DMXDEV_STATE_GO: indicates that the filter is running. + * @DMXDEV_STATE_DONE: indicates that a packet was already filtered + * and the filter is now disabled. + * Set only if %DMX_ONESHOT. See + * &dmx_sct_filter_params. + * @DMXDEV_STATE_TIMEDOUT: Indicates a timeout condition. + */ +enum dmxdev_state { + DMXDEV_STATE_FREE, + DMXDEV_STATE_ALLOCATED, + DMXDEV_STATE_SET, + DMXDEV_STATE_GO, + DMXDEV_STATE_DONE, + DMXDEV_STATE_TIMEDOUT +}; + +/** + * struct dmxdev_feed - digital TV dmxdev feed + * + * @pid: Program ID to be filtered + * @ts: pointer to &struct dmx_ts_feed + * @next: &struct list_head pointing to the next feed. + */ + +struct dmxdev_feed { + u16 pid; + struct dmx_ts_feed *ts; + struct list_head next; +}; + +/** + * struct dmxdev_filter - digital TV dmxdev filter + * + * @filter: a union describing a dmxdev filter. + * Currently used only for section filters. + * @filter.sec: a &struct dmx_section_filter pointer. + * For section filter only. + * @feed: a union describing a dmxdev feed. + * Depending on the filter type, it can be either + * @feed.ts or @feed.sec. + * @feed.ts: a &struct list_head list. + * For TS and PES feeds. + * @feed.sec: a &struct dmx_section_feed pointer. + * For section feed only. + * @params: a union describing dmxdev filter parameters. + * Depending on the filter type, it can be either + * @params.sec or @params.pes. + * @params.sec: a &struct dmx_sct_filter_params embedded struct. + * For section filter only. + * @params.pes: a &struct dmx_pes_filter_params embedded struct. + * For PES filter only. + * @type: type of the dmxdev filter, as defined by &enum dmxdev_type. + * @state: state of the dmxdev filter, as defined by &enum dmxdev_state. + * @dev: pointer to &struct dmxdev. + * @buffer: an embedded &struct dvb_ringbuffer buffer. + * @vb2_ctx: control struct for VB2 handler + * @mutex: protects the access to &struct dmxdev_filter. + * @timer: &struct timer_list embedded timer, used to check for + * feed timeouts. + * Only for section filter. + * @todo: index for the @secheader. + * Only for section filter. + * @secheader: buffer cache to parse the section header. + * Only for section filter. + */ +struct dmxdev_filter { + union { + struct dmx_section_filter *sec; + } filter; + + union { + /* list of TS and PES feeds (struct dmxdev_feed) */ + struct list_head ts; + struct dmx_section_feed *sec; + } feed; + + union { + struct dmx_sct_filter_params sec; + struct dmx_pes_filter_params pes; + } params; + + enum dmxdev_type type; + enum dmxdev_state state; + struct dmxdev *dev; + struct dvb_ringbuffer buffer; +#ifdef CONFIG_DVB_MMAP + struct dvb_vb2_ctx vb2_ctx; +#endif + + struct mutex mutex; + + /* only for sections */ + struct timer_list timer; + int todo; + u8 secheader[3]; +}; + +/** + * struct dmxdev - Describes a digital TV demux device. + * + * @dvbdev: pointer to &struct dvb_device associated with + * the demux device node. + * @dvr_dvbdev: pointer to &struct dvb_device associated with + * the dvr device node. + * @filter: pointer to &struct dmxdev_filter. + * @demux: pointer to &struct dmx_demux. + * @filternum: number of filters. + * @capabilities: demux capabilities as defined by &enum dmx_demux_caps. + * @may_do_mmap: flag used to indicate if the device may do mmap. + * @exit: flag to indicate that the demux is being released. + * @dvr_orig_fe: pointer to &struct dmx_frontend. + * @dvr_buffer: embedded &struct dvb_ringbuffer for DVB output. + * @dvr_vb2_ctx: control struct for VB2 handler + * @mutex: protects the usage of this structure. + * @lock: protects access to &dmxdev->filter->data. + */ +struct dmxdev { + struct dvb_device *dvbdev; + struct dvb_device *dvr_dvbdev; + + struct dmxdev_filter *filter; + struct dmx_demux *demux; + + int filternum; + int capabilities; + + unsigned int may_do_mmap:1; + unsigned int exit:1; +#define DMXDEV_CAP_DUPLEX 1 + struct dmx_frontend *dvr_orig_fe; + + struct dvb_ringbuffer dvr_buffer; +#define DVR_BUFFER_SIZE (10*188*1024) + +#ifdef CONFIG_DVB_MMAP + struct dvb_vb2_ctx dvr_vb2_ctx; +#endif + + struct mutex mutex; + spinlock_t lock; +}; + +/** + * dvb_dmxdev_init - initializes a digital TV demux and registers both demux + * and DVR devices. + * + * @dmxdev: pointer to &struct dmxdev. + * @adap: pointer to &struct dvb_adapter. + */ +int dvb_dmxdev_init(struct dmxdev *dmxdev, struct dvb_adapter *adap); + +/** + * dvb_dmxdev_release - releases a digital TV demux and unregisters it. + * + * @dmxdev: pointer to &struct dmxdev. + */ +void dvb_dmxdev_release(struct dmxdev *dmxdev); + +#endif /* _DMXDEV_H_ */ diff --git a/dvb-core/dvb_ca_en50221.h b/include/linux/media/dvb_ca_en50221.h similarity index 99% rename from dvb-core/dvb_ca_en50221.h rename to include/linux/media/dvb_ca_en50221.h index 367687d..a1c014b 100644 --- a/dvb-core/dvb_ca_en50221.h +++ b/include/linux/media/dvb_ca_en50221.h @@ -20,7 +20,7 @@ #include #include -#include "dvbdev.h" +#include #define DVB_CA_EN50221_POLL_CAM_PRESENT 1 #define DVB_CA_EN50221_POLL_CAM_CHANGED 2 diff --git a/include/linux/media/dvb_demux.h b/include/linux/media/dvb_demux.h new file mode 100644 index 0000000..3b6aeca --- /dev/null +++ b/include/linux/media/dvb_demux.h @@ -0,0 +1,354 @@ +/* + * dvb_demux.h: DVB kernel demux API + * + * Copyright (C) 2000-2001 Marcus Metzler & Ralph Metzler + * for convergence integrated media GmbH + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public License + * as published by the Free Software Foundation; either version 2.1 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + */ + +#ifndef _DVB_DEMUX_H_ +#define _DVB_DEMUX_H_ + +#include +#include +#include +#include + +#include + +/** + * enum dvb_dmx_filter_type - type of demux feed. + * + * @DMX_TYPE_TS: feed is in TS mode. + * @DMX_TYPE_SEC: feed is in Section mode. + */ +enum dvb_dmx_filter_type { + DMX_TYPE_TS, + DMX_TYPE_SEC, +}; + +/** + * enum dvb_dmx_state - state machine for a demux filter. + * + * @DMX_STATE_FREE: indicates that the filter is freed. + * @DMX_STATE_ALLOCATED: indicates that the filter was allocated + * to be used. + * @DMX_STATE_READY: indicates that the filter is ready + * to be used. + * @DMX_STATE_GO: indicates that the filter is running. + */ +enum dvb_dmx_state { + DMX_STATE_FREE, + DMX_STATE_ALLOCATED, + DMX_STATE_READY, + DMX_STATE_GO, +}; + +#define DVB_DEMUX_MASK_MAX 18 + +#define MAX_PID 0x1fff + +#define SPEED_PKTS_INTERVAL 50000 + +/** + * struct dvb_demux_filter - Describes a DVB demux section filter. + * + * @filter: Section filter as defined by &struct dmx_section_filter. + * @maskandmode: logical ``and`` bit mask. + * @maskandnotmode: logical ``and not`` bit mask. + * @doneq: flag that indicates when a filter is ready. + * @next: pointer to the next section filter. + * @feed: &struct dvb_demux_feed pointer. + * @index: index of the used demux filter. + * @state: state of the filter as described by &enum dvb_dmx_state. + * @type: type of the filter as described + * by &enum dvb_dmx_filter_type. + */ + +struct dvb_demux_filter { + struct dmx_section_filter filter; + u8 maskandmode[DMX_MAX_FILTER_SIZE]; + u8 maskandnotmode[DMX_MAX_FILTER_SIZE]; + bool doneq; + + struct dvb_demux_filter *next; + struct dvb_demux_feed *feed; + int index; + enum dvb_dmx_state state; + enum dvb_dmx_filter_type type; + + /* private: used only by av7110 */ + u16 hw_handle; +}; + +/** + * struct dvb_demux_feed - describes a DVB field + * + * @feed: a union describing a digital TV feed. + * Depending on the feed type, it can be either + * @feed.ts or @feed.sec. + * @feed.ts: a &struct dmx_ts_feed pointer. + * For TS feed only. + * @feed.sec: a &struct dmx_section_feed pointer. + * For section feed only. + * @cb: a union describing digital TV callbacks. + * Depending on the feed type, it can be either + * @cb.ts or @cb.sec. + * @cb.ts: a dmx_ts_cb() calback function pointer. + * For TS feed only. + * @cb.sec: a dmx_section_cb() callback function pointer. + * For section feed only. + * @demux: pointer to &struct dvb_demux. + * @priv: private data that can optionally be used by a DVB driver. + * @type: type of the filter, as defined by &enum dvb_dmx_filter_type. + * @state: state of the filter as defined by &enum dvb_dmx_state. + * @pid: PID to be filtered. + * @timeout: feed timeout. + * @filter: pointer to &struct dvb_demux_filter. + * @buffer_flags: Buffer flags used to report discontinuity users via DVB + * memory mapped API, as defined by &enum dmx_buffer_flags. + * @ts_type: type of TS, as defined by &enum ts_filter_type. + * @pes_type: type of PES, as defined by &enum dmx_ts_pes. + * @cc: MPEG-TS packet continuity counter + * @pusi_seen: if true, indicates that a discontinuity was detected. + * it is used to prevent feeding of garbage from previous section. + * @peslen: length of the PES (Packet Elementary Stream). + * @list_head: head for the list of digital TV demux feeds. + * @index: a unique index for each feed. Can be used as hardware + * pid filter index. + */ +struct dvb_demux_feed { + union { + struct dmx_ts_feed ts; + struct dmx_section_feed sec; + } feed; + + union { + dmx_ts_cb ts; + dmx_section_cb sec; + } cb; + + struct dvb_demux *demux; + void *priv; + enum dvb_dmx_filter_type type; + enum dvb_dmx_state state; + u16 pid; + + ktime_t timeout; + struct dvb_demux_filter *filter; + + u32 buffer_flags; + + enum ts_filter_type ts_type; + enum dmx_ts_pes pes_type; + + int cc; + bool pusi_seen; + + u16 peslen; + + struct list_head list_head; + unsigned int index; +}; + +/** + * struct dvb_demux - represents a digital TV demux + * @dmx: embedded &struct dmx_demux with demux capabilities + * and callbacks. + * @priv: private data that can optionally be used by + * a DVB driver. + * @filternum: maximum amount of DVB filters. + * @feednum: maximum amount of DVB feeds. + * @start_feed: callback routine to be called in order to start + * a DVB feed. + * @stop_feed: callback routine to be called in order to stop + * a DVB feed. + * @write_to_decoder: callback routine to be called if the feed is TS and + * it is routed to an A/V decoder, when a new TS packet + * is received. + * Used only on av7110-av.c. + * @check_crc32: callback routine to check CRC. If not initialized, + * dvb_demux will use an internal one. + * @memcopy: callback routine to memcopy received data. + * If not initialized, dvb_demux will default to memcpy(). + * @users: counter for the number of demux opened file descriptors. + * Currently, it is limited to 10 users. + * @filter: pointer to &struct dvb_demux_filter. + * @feed: pointer to &struct dvb_demux_feed. + * @frontend_list: &struct list_head with frontends used by the demux. + * @pesfilter: array of &struct dvb_demux_feed with the PES types + * that will be filtered. + * @pids: list of filtered program IDs. + * @feed_list: &struct list_head with feeds. + * @tsbuf: temporary buffer used internally to store TS packets. + * @tsbufp: temporary buffer index used internally. + * @mutex: pointer to &struct mutex used to protect feed set + * logic. + * @lock: pointer to &spinlock_t, used to protect buffer handling. + * @cnt_storage: buffer used for TS/TEI continuity check. + * @speed_last_time: &ktime_t used for TS speed check. + * @speed_pkts_cnt: packets count used for TS speed check. + */ +struct dvb_demux { + struct dmx_demux dmx; + void *priv; + int filternum; + int feednum; + int (*start_feed)(struct dvb_demux_feed *feed); + int (*stop_feed)(struct dvb_demux_feed *feed); + int (*write_to_decoder)(struct dvb_demux_feed *feed, + const u8 *buf, size_t len); + u32 (*check_crc32)(struct dvb_demux_feed *feed, + const u8 *buf, size_t len); + void (*memcopy)(struct dvb_demux_feed *feed, u8 *dst, + const u8 *src, size_t len); + + int users; +#define MAX_DVB_DEMUX_USERS 10 + struct dvb_demux_filter *filter; + struct dvb_demux_feed *feed; + + struct list_head frontend_list; + + struct dvb_demux_feed *pesfilter[DMX_PES_OTHER]; + u16 pids[DMX_PES_OTHER]; + +#define DMX_MAX_PID 0x2000 + struct list_head feed_list; + u8 tsbuf[204]; + int tsbufp; + + struct mutex mutex; + spinlock_t lock; + + uint8_t *cnt_storage; /* for TS continuity check */ + + ktime_t speed_last_time; /* for TS speed check */ + uint32_t speed_pkts_cnt; /* for TS speed check */ + + /* private: used only on av7110 */ + int playing; + int recording; +}; + +/** + * dvb_dmx_init - initialize a digital TV demux struct. + * + * @demux: &struct dvb_demux to be initialized. + * + * Before being able to register a digital TV demux struct, drivers + * should call this routine. On its typical usage, some fields should + * be initialized at the driver before calling it. + * + * A typical usecase is:: + * + * dvb->demux.dmx.capabilities = + * DMX_TS_FILTERING | DMX_SECTION_FILTERING | + * DMX_MEMORY_BASED_FILTERING; + * dvb->demux.priv = dvb; + * dvb->demux.filternum = 256; + * dvb->demux.feednum = 256; + * dvb->demux.start_feed = driver_start_feed; + * dvb->demux.stop_feed = driver_stop_feed; + * ret = dvb_dmx_init(&dvb->demux); + * if (ret < 0) + * return ret; + */ +int dvb_dmx_init(struct dvb_demux *demux); + +/** + * dvb_dmx_release - releases a digital TV demux internal buffers. + * + * @demux: &struct dvb_demux to be released. + * + * The DVB core internally allocates data at @demux. This routine + * releases those data. Please notice that the struct itelf is not + * released, as it can be embedded on other structs. + */ +void dvb_dmx_release(struct dvb_demux *demux); + +/** + * dvb_dmx_swfilter_packets - use dvb software filter for a buffer with + * multiple MPEG-TS packets with 188 bytes each. + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data to be filtered + * @count: number of MPEG-TS packets with size of 188. + * + * The routine will discard a DVB packet that don't start with 0x47. + * + * Use this routine if the DVB demux fills MPEG-TS buffers that are + * already aligned. + * + * NOTE: The @buf size should have size equal to ``count * 188``. + */ +void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf, + size_t count); + +/** + * dvb_dmx_swfilter - use dvb software filter for a buffer with + * multiple MPEG-TS packets with 188 bytes each. + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data to be filtered + * @count: number of MPEG-TS packets with size of 188. + * + * If a DVB packet doesn't start with 0x47, it will seek for the first + * byte that starts with 0x47. + * + * Use this routine if the DVB demux fill buffers that may not start with + * a packet start mark (0x47). + * + * NOTE: The @buf size should have size equal to ``count * 188``. + */ +void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count); + +/** + * dvb_dmx_swfilter_204 - use dvb software filter for a buffer with + * multiple MPEG-TS packets with 204 bytes each. + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data to be filtered + * @count: number of MPEG-TS packets with size of 204. + * + * If a DVB packet doesn't start with 0x47, it will seek for the first + * byte that starts with 0x47. + * + * Use this routine if the DVB demux fill buffers that may not start with + * a packet start mark (0x47). + * + * NOTE: The @buf size should have size equal to ``count * 204``. + */ +void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, + size_t count); + +/** + * dvb_dmx_swfilter_raw - make the raw data available to userspace without + * filtering + * + * @demux: pointer to &struct dvb_demux + * @buf: buffer with data + * @count: number of packets to be passed. The actual size of each packet + * depends on the &dvb_demux->feed->cb.ts logic. + * + * Use it if the driver needs to deliver the raw payload to userspace without + * passing through the kernel demux. That is meant to support some + * delivery systems that aren't based on MPEG-TS. + * + * This function relies on &dvb_demux->feed->cb.ts to actually handle the + * buffer. + */ +void dvb_dmx_swfilter_raw(struct dvb_demux *demux, const u8 *buf, + size_t count); + +#endif /* _DVB_DEMUX_H_ */ diff --git a/dvb-core/dvb_filter.h b/include/linux/media/dvb_filter.h similarity index 100% rename from dvb-core/dvb_filter.h rename to include/linux/media/dvb_filter.h diff --git a/dvb-core/dvb_frontend.h b/include/linux/media/dvb_frontend.h similarity index 83% rename from dvb-core/dvb_frontend.h rename to include/linux/media/dvb_frontend.h index b5c48b5..2132da2 100644 --- a/dvb-core/dvb_frontend.h +++ b/include/linux/media/dvb_frontend.h @@ -46,10 +46,11 @@ #include #include #include +#include #include -#include "dvbdev.h" +#include /* * Maximum number of Delivery systems per frontend. It @@ -57,6 +58,10 @@ */ #define MAX_DELSYS 16 +/* Helper definitions to be used at frontend drivers */ +#define kHz 1000UL +#define MHz 1000000UL + /** * struct dvb_frontend_tune_settings - parameters to adjust frontend tuning * @@ -78,22 +83,19 @@ struct dvb_frontend; * struct dvb_tuner_info - Frontend name and min/max ranges/bandwidths * * @name: name of the Frontend - * @frequency_min: minimal frequency supported - * @frequency_max: maximum frequency supported - * @frequency_step: frequency step + * @frequency_min_hz: minimal frequency supported in Hz + * @frequency_max_hz: maximum frequency supported in Hz + * @frequency_step_hz: frequency step in Hz * @bandwidth_min: minimal frontend bandwidth supported * @bandwidth_max: maximum frontend bandwidth supported * @bandwidth_step: frontend bandwidth step - * - * NOTE: frequency parameters are in Hz, for terrestrial/cable or kHz for - * satellite. */ struct dvb_tuner_info { char name[128]; - u32 frequency_min; - u32 frequency_max; - u32 frequency_step; + u32 frequency_min_hz; + u32 frequency_max_hz; + u32 frequency_step_hz; u32 bandwidth_min; u32 bandwidth_max; @@ -104,10 +106,10 @@ struct dvb_tuner_info { * struct analog_parameters - Parameters to tune into an analog/radio channel * * @frequency: Frequency used by analog TV tuner (either in 62.5 kHz step, - * for TV, or 62.5 Hz for radio) + * for TV, or 62.5 Hz for radio) * @mode: Tuner mode, as defined on enum v4l2_tuner_type * @audmode: Audio mode as defined for the rxsubchans field at videodev2.h, - * e. g. V4L2_TUNER_MODE_* + * e. g. V4L2_TUNER_MODE_* * @std: TV standard bitmap as defined at videodev2.h, e. g. V4L2_STD_* * * Hybrid tuners should be supported by both V4L2 and DVB APIs. This @@ -145,10 +147,10 @@ struct analog_parameters { * These devices have AUTO recovery capabilities from LOCK failure */ enum dvbfe_algo { - DVBFE_ALGO_HW = (1 << 0), - DVBFE_ALGO_SW = (1 << 1), - DVBFE_ALGO_CUSTOM = (1 << 2), - DVBFE_ALGO_RECOVERY = (1 << 31) + DVBFE_ALGO_HW = BIT(0), + DVBFE_ALGO_SW = BIT(1), + DVBFE_ALGO_CUSTOM = BIT(2), + DVBFE_ALGO_RECOVERY = BIT(31), }; /** @@ -164,7 +166,7 @@ enum dvbfe_algo { * The frontend search for a signal failed * * @DVBFE_ALGO_SEARCH_INVALID: - * The frontend search algorith was probably supplied with invalid + * The frontend search algorithm was probably supplied with invalid * parameters and the search is an invalid one * * @DVBFE_ALGO_SEARCH_ERROR: @@ -174,19 +176,19 @@ enum dvbfe_algo { * The frontend search algorithm was requested to search again */ enum dvbfe_search { - DVBFE_ALGO_SEARCH_SUCCESS = (1 << 0), - DVBFE_ALGO_SEARCH_ASLEEP = (1 << 1), - DVBFE_ALGO_SEARCH_FAILED = (1 << 2), - DVBFE_ALGO_SEARCH_INVALID = (1 << 3), - DVBFE_ALGO_SEARCH_AGAIN = (1 << 4), - DVBFE_ALGO_SEARCH_ERROR = (1 << 31), + DVBFE_ALGO_SEARCH_SUCCESS = BIT(0), + DVBFE_ALGO_SEARCH_ASLEEP = BIT(1), + DVBFE_ALGO_SEARCH_FAILED = BIT(2), + DVBFE_ALGO_SEARCH_INVALID = BIT(3), + DVBFE_ALGO_SEARCH_AGAIN = BIT(4), + DVBFE_ALGO_SEARCH_ERROR = BIT(31), }; /** * struct dvb_tuner_ops - Tuner information and callbacks * - * @info: embedded struct dvb_tuner_info with tuner properties - * @release: callback function called when frontend is dettached. + * @info: embedded &struct dvb_tuner_info with tuner properties + * @release: callback function called when frontend is detached. * drivers should free any allocated memory. * @init: callback function used to initialize the tuner device. * @sleep: callback function used to put the tuner to sleep. @@ -196,25 +198,25 @@ enum dvbfe_search { * resuming from suspend. * @set_params: callback function used to inform the tuner to tune * into a digital TV channel. The properties to be used - * are stored at @dvb_frontend.dtv_property_cache;. The - * tuner demod can change the parameters to reflect the - * changes needed for the channel to be tuned, and + * are stored at &struct dvb_frontend.dtv_property_cache. + * The tuner demod can change the parameters to reflect + * the changes needed for the channel to be tuned, and * update statistics. This is the recommended way to set * the tuner parameters and should be used on newer * drivers. * @set_analog_params: callback function used to tune into an analog TV - * channel on hybrid tuners. It passes @analog_parameters; + * channel on hybrid tuners. It passes @analog_parameters * to the driver. * @set_config: callback function used to send some tuner-specific * parameters. * @get_frequency: get the actual tuned frequency - * @get_bandwidth: get the bandwitdh used by the low pass filters + * @get_bandwidth: get the bandwidth used by the low pass filters * @get_if_frequency: get the Intermediate Frequency, in Hz. For baseband, - * should return 0. + * should return 0. * @get_status: returns the frontend lock status - * @get_rf_strength: returns the RF signal strengh. Used mostly to support + * @get_rf_strength: returns the RF signal strength. Used mostly to support * analog TV and radio. Digital TV should report, instead, - * via DVBv5 API (@dvb_frontend.dtv_property_cache;). + * via DVBv5 API (&struct dvb_frontend.dtv_property_cache). * @get_afc: Used only by analog TV core. Reports the frequency * drift due to AFC. * @calc_regs: callback function used to pass register data settings @@ -222,7 +224,7 @@ enum dvbfe_search { * @set_frequency: Set a new frequency. Shouldn't be used on newer drivers. * @set_bandwidth: Set a new frequency. Shouldn't be used on newer drivers. * - * NOTE: frequencies used on get_frequency and set_frequency are in Hz for + * NOTE: frequencies used on @get_frequency and @set_frequency are in Hz for * terrestrial/cable or kHz for satellite. * */ @@ -236,7 +238,7 @@ struct dvb_tuner_ops { int (*suspend)(struct dvb_frontend *fe); int (*resume)(struct dvb_frontend *fe); - /* This is the recomended way to set the tuner */ + /* This is the recommended way to set the tuner */ int (*set_params)(struct dvb_frontend *fe); int (*set_analog_params)(struct dvb_frontend *fe, struct analog_parameters *p); @@ -288,14 +290,14 @@ struct analog_demod_info { * @set_params: callback function used to inform the demod to set the * demodulator parameters needed to decode an analog or * radio channel. The properties are passed via - * struct @analog_params;. + * &struct analog_params. * @has_signal: returns 0xffff if has signal, or 0 if it doesn't. * @get_afc: Used only by analog TV core. Reports the frequency * drift due to AFC. * @tuner_status: callback function that returns tuner status bits, e. g. - * TUNER_STATUS_LOCKED and TUNER_STATUS_STEREO. + * %TUNER_STATUS_LOCKED and %TUNER_STATUS_STEREO. * @standby: set the tuner to standby mode. - * @release: callback function called when frontend is dettached. + * @release: callback function called when frontend is detached. * drivers should free any allocated memory. * @i2c_gate_ctrl: controls the I2C gate. Newer drivers should use I2C * mux support instead. @@ -321,20 +323,48 @@ struct analog_demod_ops { struct dtv_frontend_properties; +/** + * struct dvb_frontend_internal_info - Frontend properties and capabilities + * + * @name: Name of the frontend + * @frequency_min_hz: Minimal frequency supported by the frontend. + * @frequency_max_hz: Minimal frequency supported by the frontend. + * @frequency_stepsize_hz: All frequencies are multiple of this value. + * @frequency_tolerance_hz: Frequency tolerance. + * @symbol_rate_min: Minimal symbol rate, in bauds + * (for Cable/Satellite systems). + * @symbol_rate_max: Maximal symbol rate, in bauds + * (for Cable/Satellite systems). + * @symbol_rate_tolerance: Maximal symbol rate tolerance, in ppm + * (for Cable/Satellite systems). + * @caps: Capabilities supported by the frontend, + * as specified in &enum fe_caps. + */ +struct dvb_frontend_internal_info { + char name[128]; + u32 frequency_min_hz; + u32 frequency_max_hz; + u32 frequency_stepsize_hz; + u32 frequency_tolerance_hz; + u32 symbol_rate_min; + u32 symbol_rate_max; + u32 symbol_rate_tolerance; + enum fe_caps caps; +}; /** * struct dvb_frontend_ops - Demodulation information and callbacks for * ditialt TV * - * @info: embedded struct dvb_tuner_info with tuner properties + * @info: embedded &struct dvb_tuner_info with tuner properties * @delsys: Delivery systems supported by the frontend * @detach: callback function called when frontend is detached. - * drivers should clean up, but not yet free the struct + * drivers should clean up, but not yet free the &struct * dvb_frontend allocation. * @release: callback function called when frontend is ready to be * freed. * drivers should free any allocated memory. - * @release_sec: callback function requesting that the Satelite Equipment + * @release_sec: callback function requesting that the Satellite Equipment * Control (SEC) driver to release and free any memory * allocated by the driver. * @init: callback function used to initialize the tuner device. @@ -343,57 +373,57 @@ struct dtv_frontend_properties; * allow other drivers to write data into their registers. * Should not be used on new drivers. * @tune: callback function used by demod drivers that use - * @DVBFE_ALGO_HW; to tune into a frequency. + * @DVBFE_ALGO_HW to tune into a frequency. * @get_frontend_algo: returns the desired hardware algorithm. * @set_frontend: callback function used to inform the demod to set the * parameters for demodulating a digital TV channel. - * The properties to be used are stored at - * @dvb_frontend.dtv_property_cache;. The demod can change + * The properties to be used are stored at &struct + * dvb_frontend.dtv_property_cache. The demod can change * the parameters to reflect the changes needed for the * channel to be decoded, and update statistics. * @get_tune_settings: callback function * @get_frontend: callback function used to inform the parameters * actuall in use. The properties to be used are stored at - * @dvb_frontend.dtv_property_cache; and update + * &struct dvb_frontend.dtv_property_cache and update * statistics. Please notice that it should not return * an error code if the statistics are not available * because the demog is not locked. * @read_status: returns the locking status of the frontend. * @read_ber: legacy callback function to return the bit error rate. * Newer drivers should provide such info via DVBv5 API, - * e. g. @set_frontend;/@get_frontend;, implementing this + * e. g. @set_frontend;/@get_frontend, implementing this * callback only if DVBv3 API compatibility is wanted. * @read_signal_strength: legacy callback function to return the signal * strength. Newer drivers should provide such info via - * DVBv5 API, e. g. @set_frontend;/@get_frontend;, + * DVBv5 API, e. g. @set_frontend/@get_frontend, * implementing this callback only if DVBv3 API * compatibility is wanted. * @read_snr: legacy callback function to return the Signal/Noise - * rate. Newer drivers should provide such info via - * DVBv5 API, e. g. @set_frontend;/@get_frontend;, + * rate. Newer drivers should provide such info via + * DVBv5 API, e. g. @set_frontend/@get_frontend, * implementing this callback only if DVBv3 API * compatibility is wanted. * @read_ucblocks: legacy callback function to return the Uncorrected Error * Blocks. Newer drivers should provide such info via - * DVBv5 API, e. g. @set_frontend;/@get_frontend;, + * DVBv5 API, e. g. @set_frontend/@get_frontend, * implementing this callback only if DVBv3 API * compatibility is wanted. * @diseqc_reset_overload: callback function to implement the - * FE_DISEQC_RESET_OVERLOAD ioctl (only Satellite) + * FE_DISEQC_RESET_OVERLOAD() ioctl (only Satellite) * @diseqc_send_master_cmd: callback function to implement the - * FE_DISEQC_SEND_MASTER_CMD ioctl (only Satellite). + * FE_DISEQC_SEND_MASTER_CMD() ioctl (only Satellite). * @diseqc_recv_slave_reply: callback function to implement the - * FE_DISEQC_RECV_SLAVE_REPLY ioctl (only Satellite) + * FE_DISEQC_RECV_SLAVE_REPLY() ioctl (only Satellite) * @diseqc_send_burst: callback function to implement the - * FE_DISEQC_SEND_BURST ioctl (only Satellite). + * FE_DISEQC_SEND_BURST() ioctl (only Satellite). * @set_tone: callback function to implement the - * FE_SET_TONE ioctl (only Satellite). + * FE_SET_TONE() ioctl (only Satellite). * @set_voltage: callback function to implement the - * FE_SET_VOLTAGE ioctl (only Satellite). + * FE_SET_VOLTAGE() ioctl (only Satellite). * @enable_high_lnb_voltage: callback function to implement the - * FE_ENABLE_HIGH_LNB_VOLTAGE ioctl (only Satellite). + * FE_ENABLE_HIGH_LNB_VOLTAGE() ioctl (only Satellite). * @dishnetwork_send_legacy_command: callback function to implement the - * FE_DISHNETWORK_SEND_LEGACY_CMD ioctl (only Satellite). + * FE_DISHNETWORK_SEND_LEGACY_CMD() ioctl (only Satellite). * Drivers should not use this, except when the DVB * core emulation fails to provide proper support (e.g. * if @set_voltage takes more than 8ms to work), and @@ -404,16 +434,12 @@ struct dtv_frontend_properties; * @ts_bus_ctrl: callback function used to take control of the TS bus. * @set_lna: callback function to power on/off/auto the LNA. * @search: callback function used on some custom algo search algos. - * @tuner_ops: pointer to struct dvb_tuner_ops - * @analog_ops: pointer to struct analog_demod_ops - * @set_property: callback function to allow the frontend to validade - * incoming properties. Should not be used on new drivers. - * @get_property: callback function to allow the frontend to override - * outcoming properties. Should not be used on new drivers. + * @tuner_ops: pointer to &struct dvb_tuner_ops + * @analog_ops: pointer to &struct analog_demod_ops */ struct dvb_frontend_ops { - struct dvb_frontend_info info; + struct dvb_frontend_internal_info info; u8 delsys[MAX_DELSYS]; @@ -473,9 +499,6 @@ struct dvb_frontend_ops { struct dvb_tuner_ops tuner_ops; struct analog_demod_ops analog_ops; - int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp); - int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp); - u8 xbar[3]; }; @@ -506,7 +529,7 @@ struct dvb_fe_events { * @fec_inner: Forward error correction inner Code Rate * @transmission_mode: Transmission Mode * @bandwidth_hz: Bandwidth, in Hz. A zero value means that userspace - * wants to autodetect. + * wants to autodetect. * @guard_interval: Guard Interval * @hierarchy: Hierarchy * @symbol_rate: Symbol Rate @@ -529,8 +552,8 @@ struct dvb_fe_events { * @layer.interleaving: per layer interleaving. * @stream_id: If different than zero, enable substream filtering, if * hardware supports (DVB-S2 and DVB-T2). - * @scrambling_sequence_index: Carries the index of the DVB-S2 physical layer - * scrambling sequence. + * @scrambling_sequence_index: Carries the index of the DVB-S2 physical layer + * scrambling sequence. * @atscmh_fic_ver: Version number of the FIC (Fast Information Channel) * signaling data (only ATSC-M/H) * @atscmh_parade_id: Parade identification number (only ATSC-M/H) @@ -554,7 +577,7 @@ struct dvb_fe_events { * @lna: Power ON/OFF/AUTO the Linear Now-noise Amplifier (LNA) * @strength: DVBv5 API statistics: Signal Strength * @cnr: DVBv5 API statistics: Signal to Noise ratio of the - * (main) carrier + * (main) carrier * @pre_bit_error: DVBv5 API statistics: pre-Viterbi bit error count * @pre_bit_count: DVBv5 API statistics: pre-Viterbi bit count * @post_bit_error: DVBv5 API statistics: post-Viterbi bit error count @@ -575,15 +598,15 @@ struct dtv_frontend_properties { enum fe_sec_voltage voltage; enum fe_sec_tone_mode sectone; - enum fe_spectral_inversion inversion; - enum fe_code_rate fec_inner; + enum fe_spectral_inversion inversion; + enum fe_code_rate fec_inner; enum fe_transmit_mode transmission_mode; u32 bandwidth_hz; /* 0 = AUTO */ enum fe_guard_interval guard_interval; - enum fe_hierarchy hierarchy; + enum fe_hierarchy hierarchy; u32 symbol_rate; - enum fe_code_rate code_rate_HP; - enum fe_code_rate code_rate_LP; + enum fe_code_rate code_rate_HP; + enum fe_code_rate code_rate_LP; enum fe_pilot pilot; enum fe_rolloff rolloff; @@ -610,7 +633,7 @@ struct dtv_frontend_properties { u32 stream_id; /* Physical Layer Scrambling specifics */ - u32 scrambling_sequence_index; + u32 scrambling_sequence_index; /* ATSC-MH specifics */ u8 atscmh_fic_ver; @@ -642,11 +665,6 @@ struct dtv_frontend_properties { struct dtv_fe_stats post_bit_count; struct dtv_fe_stats block_error; struct dtv_fe_stats block_count; - - /* private: */ - /* Cache State */ - u32 state; - }; #define DVB_FE_NO_EXIT 0 @@ -657,16 +675,16 @@ struct dtv_frontend_properties { /** * struct dvb_frontend - Frontend structure to be used on drivers. * - * @refcount: refcount to keep track of struct dvb_frontend + * @refcount: refcount to keep track of &struct dvb_frontend * references - * @ops: embedded struct dvb_frontend_ops - * @dvb: pointer to struct dvb_adapter + * @ops: embedded &struct dvb_frontend_ops + * @dvb: pointer to &struct dvb_adapter * @demodulator_priv: demod private data * @tuner_priv: tuner private data * @frontend_priv: frontend private data * @sec_priv: SEC private data * @analog_demod_priv: Analog demod private data - * @dtv_property_cache: embedded struct dtv_frontend_properties + * @dtv_property_cache: embedded &struct dtv_frontend_properties * @callback: callback function used on some drivers to call * either the tuner or the demodulator. * @id: Frontend ID @@ -695,8 +713,8 @@ struct dvb_frontend { /** * dvb_register_frontend() - Registers a DVB frontend at the adapter * - * @dvb: pointer to the dvb adapter - * @fe: pointer to the frontend struct + * @dvb: pointer to &struct dvb_adapter + * @fe: pointer to &struct dvb_frontend * * Allocate and initialize the private data needed by the frontend core to * manage the frontend and calls dvb_register_device() to register a new @@ -709,7 +727,7 @@ int dvb_register_frontend(struct dvb_adapter *dvb, /** * dvb_unregister_frontend() - Unregisters a DVB frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * Stops the frontend kthread, calls dvb_unregister_device() and frees the * private frontend data allocated by dvb_register_frontend(). @@ -723,14 +741,14 @@ int dvb_unregister_frontend(struct dvb_frontend *fe); /** * dvb_frontend_detach() - Detaches and frees frontend specific data * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * This function should be called after dvb_unregister_frontend(). It * calls the SEC, tuner and demod release functions: * &dvb_frontend_ops.release_sec, &dvb_frontend_ops.tuner_ops.release, * &dvb_frontend_ops.analog_ops.release and &dvb_frontend_ops.release. * - * If the driver is compiled with CONFIG_MEDIA_ATTACH, it also decreases + * If the driver is compiled with %CONFIG_MEDIA_ATTACH, it also decreases * the module reference count, needed to allow userspace to remove the * previously used DVB frontend modules. */ @@ -739,7 +757,7 @@ void dvb_frontend_detach(struct dvb_frontend *fe); /** * dvb_frontend_suspend() - Suspends a Digital TV frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * This function prepares a Digital TV frontend to suspend. * @@ -757,7 +775,7 @@ int dvb_frontend_suspend(struct dvb_frontend *fe); /** * dvb_frontend_resume() - Resumes a Digital TV frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * This function resumes the usual operation of the tuner after resume. * @@ -778,7 +796,7 @@ int dvb_frontend_resume(struct dvb_frontend *fe); /** * dvb_frontend_reinitialise() - forces a reinitialisation at the frontend * - * @fe: pointer to the frontend struct + * @fe: pointer to &struct dvb_frontend * * Calls &dvb_frontend_ops.init\(\) and &dvb_frontend_ops.tuner_ops.init\(\), * and resets SEC tone and voltage (for Satellite systems). @@ -793,16 +811,16 @@ void dvb_frontend_reinitialise(struct dvb_frontend *fe); * dvb_frontend_sleep_until() - Sleep for the amount of time given by * add_usec parameter * - * @waketime: pointer to a struct ktime_t + * @waketime: pointer to &struct ktime_t * @add_usec: time to sleep, in microseconds * * This function is used to measure the time required for the - * %FE_DISHNETWORK_SEND_LEGACY_CMD ioctl to work. It needs to be as precise + * FE_DISHNETWORK_SEND_LEGACY_CMD() ioctl to work. It needs to be as precise * as possible, as it affects the detection of the dish tone command at the * satellite subsystem. * * Its used internally by the DVB frontend core, in order to emulate - * %FE_DISHNETWORK_SEND_LEGACY_CMD using the &dvb_frontend_ops.set_voltage\(\) + * FE_DISHNETWORK_SEND_LEGACY_CMD() using the &dvb_frontend_ops.set_voltage\(\) * callback. * * NOTE: it should not be used at the drivers, as the emulation for the diff --git a/dvb-core/dvb_math.h b/include/linux/media/dvb_math.h similarity index 100% rename from dvb-core/dvb_math.h rename to include/linux/media/dvb_math.h diff --git a/dvb-core/dvb_net.h b/include/linux/media/dvb_net.h similarity index 56% rename from dvb-core/dvb_net.h rename to include/linux/media/dvb_net.h index e9b18aa..5e31d37 100644 --- a/dvb-core/dvb_net.h +++ b/include/linux/media/dvb_net.h @@ -24,12 +24,28 @@ #include #include -#include "dvbdev.h" +#include #define DVB_NET_DEVICES_MAX 10 #ifdef CONFIG_DVB_NET +/** + * struct dvb_net - describes a DVB network interface + * + * @dvbdev: pointer to &struct dvb_device. + * @device: array of pointers to &struct net_device. + * @state: array of integers to each net device. A value + * different than zero means that the interface is + * in usage. + * @exit: flag to indicate when the device is being removed. + * @demux: pointer to &struct dmx_demux. + * @ioctl_mutex: protect access to this struct. + * + * Currently, the core supports up to %DVB_NET_DEVICES_MAX (10) network + * devices. + */ + struct dvb_net { struct dvb_device *dvbdev; struct net_device *device[DVB_NET_DEVICES_MAX]; @@ -39,8 +55,22 @@ struct dvb_net { struct mutex ioctl_mutex; }; -void dvb_net_release(struct dvb_net *); -int dvb_net_init(struct dvb_adapter *, struct dvb_net *, struct dmx_demux *); +/** + * dvb_net_init - nitializes a digital TV network device and registers it. + * + * @adap: pointer to &struct dvb_adapter. + * @dvbnet: pointer to &struct dvb_net. + * @dmxdemux: pointer to &struct dmx_demux. + */ +int dvb_net_init(struct dvb_adapter *adap, struct dvb_net *dvbnet, + struct dmx_demux *dmxdemux); + +/** + * dvb_net_release - releases a digital TV network device and unregisters it. + * + * @dvbnet: pointer to &struct dvb_net. + */ +void dvb_net_release(struct dvb_net *dvbnet); #else diff --git a/dvb-core/dvb_ringbuffer.h b/include/linux/media/dvb_ringbuffer.h similarity index 100% rename from dvb-core/dvb_ringbuffer.h rename to include/linux/media/dvb_ringbuffer.h diff --git a/include/linux/media/dvb_vb2.h b/include/linux/media/dvb_vb2.h new file mode 100644 index 0000000..8cb8845 --- /dev/null +++ b/include/linux/media/dvb_vb2.h @@ -0,0 +1,280 @@ +/* + * SPDX-License-Identifier: GPL-2.0 + * + * dvb-vb2.h - DVB driver helper framework for streaming I/O + * + * Copyright (C) 2015 Samsung Electronics + * + * Author: jh1009.sung@samsung.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation. + */ + +#ifndef _DVB_VB2_H +#define _DVB_VB2_H + +#include +#include +#include +#include +#include +#include + +/** + * enum dvb_buf_type - types of Digital TV memory-mapped buffers + * + * @DVB_BUF_TYPE_CAPTURE: buffer is filled by the Kernel, + * with a received Digital TV stream + */ +enum dvb_buf_type { + DVB_BUF_TYPE_CAPTURE = 1, +}; + +/** + * enum dvb_vb2_states - states to control VB2 state machine + * @DVB_VB2_STATE_NONE: + * VB2 engine not initialized yet, init failed or VB2 was released. + * @DVB_VB2_STATE_INIT: + * VB2 engine initialized. + * @DVB_VB2_STATE_REQBUFS: + * Buffers were requested + * @DVB_VB2_STATE_STREAMON: + * VB2 is streaming. Callers should not check it directly. Instead, + * they should use dvb_vb2_is_streaming(). + * + * Note: + * + * Callers should not touch at the state machine directly. This + * is handled inside dvb_vb2.c. + */ +enum dvb_vb2_states { + DVB_VB2_STATE_NONE = 0x0, + DVB_VB2_STATE_INIT = 0x1, + DVB_VB2_STATE_REQBUFS = 0x2, + DVB_VB2_STATE_STREAMON = 0x4, +}; + +#define DVB_VB2_NAME_MAX (20) + +/** + * struct dvb_buffer - video buffer information for v4l2. + * + * @vb: embedded struct &vb2_buffer. + * @list: list of &struct dvb_buffer. + */ +struct dvb_buffer { + struct vb2_buffer vb; + struct list_head list; +}; + +/** + * struct dvb_vb2_ctx - control struct for VB2 handler + * @vb_q: pointer to &struct vb2_queue with videobuf2 queue. + * @mutex: mutex to serialize vb2 operations. Used by + * vb2 core %wait_prepare and %wait_finish operations. + * @slock: spin lock used to protect buffer filling at dvb_vb2.c. + * @dvb_q: List of buffers that are not filled yet. + * @buf: Pointer to the buffer that are currently being filled. + * @offset: index to the next position at the @buf to be filled. + * @remain: How many bytes are left to be filled at @buf. + * @state: bitmask of buffer states as defined by &enum dvb_vb2_states. + * @buf_siz: size of each VB2 buffer. + * @buf_cnt: number of VB2 buffers. + * @nonblocking: + * If different than zero, device is operating on non-blocking + * mode. + * @flags: buffer flags as defined by &enum dmx_buffer_flags. + * Filled only at &DMX_DQBUF. &DMX_QBUF should zero this field. + * @count: monotonic counter for filled buffers. Helps to identify + * data stream loses. Filled only at &DMX_DQBUF. &DMX_QBUF should + * zero this field. + * + * @name: name of the device type. Currently, it can either be + * "dvr" or "demux_filter". + */ +struct dvb_vb2_ctx { + struct vb2_queue vb_q; + struct mutex mutex; + spinlock_t slock; + struct list_head dvb_q; + struct dvb_buffer *buf; + int offset; + int remain; + int state; + int buf_siz; + int buf_cnt; + int nonblocking; + + enum dmx_buffer_flags flags; + u32 count; + + char name[DVB_VB2_NAME_MAX + 1]; +}; + +#ifndef CONFIG_DVB_MMAP +static inline int dvb_vb2_init(struct dvb_vb2_ctx *ctx, + const char *name, int non_blocking) +{ + return 0; +}; +static inline int dvb_vb2_release(struct dvb_vb2_ctx *ctx) +{ + return 0; +}; +#define dvb_vb2_is_streaming(ctx) (0) +#define dvb_vb2_fill_buffer(ctx, file, wait, flags) (0) + +static inline __poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx, + struct file *file, + poll_table *wait) +{ + return 0; +} +#else +/** + * dvb_vb2_init - initializes VB2 handler + * + * @ctx: control struct for VB2 handler + * @name: name for the VB2 handler + * @non_blocking: + * if not zero, it means that the device is at non-blocking mode + */ +int dvb_vb2_init(struct dvb_vb2_ctx *ctx, const char *name, int non_blocking); + +/** + * dvb_vb2_release - Releases the VB2 handler allocated resources and + * put @ctx at DVB_VB2_STATE_NONE state. + * @ctx: control struct for VB2 handler + */ +int dvb_vb2_release(struct dvb_vb2_ctx *ctx); + +/** + * dvb_vb2_is_streaming - checks if the VB2 handler is streaming + * @ctx: control struct for VB2 handler + * + * Return: 0 if not streaming, 1 otherwise. + */ +int dvb_vb2_is_streaming(struct dvb_vb2_ctx *ctx); + +/** + * dvb_vb2_fill_buffer - fills a VB2 buffer + * @ctx: control struct for VB2 handler + * @src: place where the data is stored + * @len: number of bytes to be copied from @src + * @buffer_flags: + * pointer to buffer flags as defined by &enum dmx_buffer_flags. + * can be NULL. + */ +int dvb_vb2_fill_buffer(struct dvb_vb2_ctx *ctx, + const unsigned char *src, int len, + enum dmx_buffer_flags *buffer_flags); + +/** + * dvb_vb2_poll - Wrapper to vb2_core_streamon() for Digital TV + * buffer handling. + * + * @ctx: control struct for VB2 handler + * @file: &struct file argument passed to the poll + * file operation handler. + * @wait: &poll_table wait argument passed to the poll + * file operation handler. + * + * Implements poll syscall() logic. + */ +__poll_t dvb_vb2_poll(struct dvb_vb2_ctx *ctx, struct file *file, + poll_table *wait); +#endif + +/** + * dvb_vb2_stream_on() - Wrapper to vb2_core_streamon() for Digital TV + * buffer handling. + * + * @ctx: control struct for VB2 handler + * + * Starts dvb streaming + */ +int dvb_vb2_stream_on(struct dvb_vb2_ctx *ctx); +/** + * dvb_vb2_stream_off() - Wrapper to vb2_core_streamoff() for Digital TV + * buffer handling. + * + * @ctx: control struct for VB2 handler + * + * Stops dvb streaming + */ +int dvb_vb2_stream_off(struct dvb_vb2_ctx *ctx); + +/** + * dvb_vb2_reqbufs() - Wrapper to vb2_core_reqbufs() for Digital TV + * buffer handling. + * + * @ctx: control struct for VB2 handler + * @req: &struct dmx_requestbuffers passed from userspace in + * order to handle &DMX_REQBUFS. + * + * Initiate streaming by requesting a number of buffers. Also used to + * free previously requested buffers, is ``req->count`` is zero. + */ +int dvb_vb2_reqbufs(struct dvb_vb2_ctx *ctx, struct dmx_requestbuffers *req); + +/** + * dvb_vb2_querybuf() - Wrapper to vb2_core_querybuf() for Digital TV + * buffer handling. + * + * @ctx: control struct for VB2 handler + * @b: &struct dmx_buffer passed from userspace in + * order to handle &DMX_QUERYBUF. + * + * + */ +int dvb_vb2_querybuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b); + +/** + * dvb_vb2_expbuf() - Wrapper to vb2_core_expbuf() for Digital TV + * buffer handling. + * + * @ctx: control struct for VB2 handler + * @exp: &struct dmx_exportbuffer passed from userspace in + * order to handle &DMX_EXPBUF. + * + * Export a buffer as a file descriptor. + */ +int dvb_vb2_expbuf(struct dvb_vb2_ctx *ctx, struct dmx_exportbuffer *exp); + +/** + * dvb_vb2_qbuf() - Wrapper to vb2_core_qbuf() for Digital TV buffer handling. + * + * @ctx: control struct for VB2 handler + * @b: &struct dmx_buffer passed from userspace in + * order to handle &DMX_QBUF. + * + * Queue a Digital TV buffer as requested by userspace + */ +int dvb_vb2_qbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b); + +/** + * dvb_vb2_dqbuf() - Wrapper to vb2_core_dqbuf() for Digital TV + * buffer handling. + * + * @ctx: control struct for VB2 handler + * @b: &struct dmx_buffer passed from userspace in + * order to handle &DMX_DQBUF. + * + * Dequeue a Digital TV buffer to the userspace + */ +int dvb_vb2_dqbuf(struct dvb_vb2_ctx *ctx, struct dmx_buffer *b); + +/** + * dvb_vb2_mmap() - Wrapper to vb2_mmap() for Digital TV buffer handling. + * + * @ctx: control struct for VB2 handler + * @vma: pointer to &struct vm_area_struct with the vma passed + * to the mmap file operation handler in the driver. + * + * map Digital TV video buffers into application address space. + */ +int dvb_vb2_mmap(struct dvb_vb2_ctx *ctx, struct vm_area_struct *vma); + +#endif /* _DVB_VB2_H */ diff --git a/dvb-core/dvbdev.h b/include/linux/media/dvbdev.h similarity index 59% rename from dvb-core/dvbdev.h rename to include/linux/media/dvbdev.h index f4dc90e..c4005df 100644 --- a/dvb-core/dvbdev.h +++ b/include/linux/media/dvbdev.h @@ -35,19 +35,42 @@ #define DVB_UNSET (-1) -#define DVB_DEVICE_VIDEO 0 -#define DVB_DEVICE_AUDIO 1 -#define DVB_DEVICE_SEC 2 -#define DVB_DEVICE_FRONTEND 3 -#define DVB_DEVICE_DEMUX 4 -#define DVB_DEVICE_DVR 5 -#define DVB_DEVICE_CA 6 -#define DVB_DEVICE_NET 7 -#define DVB_DEVICE_OSD 8 -#define DVB_DEVICE_CI 9 -#define DVB_DEVICE_MOD 10 -#define DVB_DEVICE_NS 11 -#define DVB_DEVICE_NSD 12 +/* List of DVB device types */ + +/** + * enum dvb_device_type - type of the Digital TV device + * + * @DVB_DEVICE_SEC: Digital TV standalone Common Interface (CI) + * @DVB_DEVICE_FRONTEND: Digital TV frontend. + * @DVB_DEVICE_DEMUX: Digital TV demux. + * @DVB_DEVICE_DVR: Digital TV digital video record (DVR). + * @DVB_DEVICE_CA: Digital TV Conditional Access (CA). + * @DVB_DEVICE_NET: Digital TV network. + * + * @DVB_DEVICE_VIDEO: Digital TV video decoder. + * Deprecated. Used only on av7110-av. + * @DVB_DEVICE_AUDIO: Digital TV audio decoder. + * Deprecated. Used only on av7110-av. + * @DVB_DEVICE_OSD: Digital TV On Screen Display (OSD). + * Deprecated. Used only on av7110. + */ +enum dvb_device_type { + DVB_DEVICE_SEC, + DVB_DEVICE_FRONTEND, + DVB_DEVICE_DEMUX, + DVB_DEVICE_DVR, + DVB_DEVICE_CA, + DVB_DEVICE_NET, + + DVB_DEVICE_VIDEO, + DVB_DEVICE_AUDIO, + DVB_DEVICE_OSD, + + DVB_DEVICE_CI, + DVB_DEVICE_MOD, + DVB_DEVICE_NS, + DVB_DEVICE_NSD, +}; #define DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr) \ static short adapter_nr[] = \ @@ -68,11 +91,12 @@ struct dvb_frontend; * @priv: private data * @device: pointer to struct device * @module: pointer to struct module - * @mfe_shared: mfe shared: indicates mutually exclusive frontends - * Thie usage of this flag is currently deprecated + * @mfe_shared: indicates mutually exclusive frontends. + * Use of this flag is currently deprecated. * @mfe_dvbdev: Frontend device in use, in the case of MFE * @mfe_lock: Lock to prevent using the other frontends when MFE is * used. + * @mdev_lock: Protect access to the mdev pointer. * @mdev: pointer to struct media_device, used when the media * controller is used. * @conn: RF connector. Used only if the device has no separate @@ -96,6 +120,7 @@ struct dvb_adapter { struct mutex mfe_lock; /* access lock for thread creation */ #if defined(CONFIG_MEDIA_CONTROLLER_DVB) + struct mutex mdev_lock; struct media_device *mdev; struct media_entity *conn; struct media_pad *conn_pads; @@ -108,8 +133,7 @@ struct dvb_adapter { * @list_head: List head with all DVB devices * @fops: pointer to struct file_operations * @adapter: pointer to the adapter that holds this device node - * @type: type of the device: DVB_DEVICE_SEC, DVB_DEVICE_FRONTEND, - * DVB_DEVICE_DEMUX, DVB_DEVICE_DVR, DVB_DEVICE_CA, DVB_DEVICE_NET + * @type: type of the device, as defined by &enum dvb_device_type. * @minor: devnode minor number. Major number is always DVB_MAJOR. * @id: device ID number, inside the adapter * @readers: Initialized by the caller. Each call to open() in Read Only mode @@ -139,7 +163,7 @@ struct dvb_device { struct list_head list_head; const struct file_operations *fops; struct dvb_adapter *adapter; - int type; + enum dvb_device_type type; int minor; u32 id; @@ -176,7 +200,7 @@ struct dvb_device { * @module: initialized with THIS_MODULE at the caller * @device: pointer to struct device that corresponds to the device driver * @adapter_nums: Array with a list of the numbers for @dvb_register_adapter; - * to select among them. Typically, initialized with: + * to select among them. Typically, initialized with: * DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nums) */ int dvb_register_adapter(struct dvb_adapter *adap, const char *name, @@ -198,9 +222,7 @@ int dvb_unregister_adapter(struct dvb_adapter *adap); * stored * @template: Template used to create &pdvbdev; * @priv: private data - * @type: type of the device: %DVB_DEVICE_SEC, %DVB_DEVICE_FRONTEND, - * %DVB_DEVICE_DEMUX, %DVB_DEVICE_DVR, %DVB_DEVICE_CA, - * %DVB_DEVICE_NET + * @type: type of the device, as defined by &enum dvb_device_type. * @demux_sink_pads: Number of demux outputs, to be used to create the TS * outputs via the Media Controller. */ @@ -208,7 +230,7 @@ int dvb_register_device(struct dvb_adapter *adap, struct dvb_device **pdvbdev, const struct dvb_device *template, void *priv, - int type, + enum dvb_device_type type, int demux_sink_pads); /** @@ -244,9 +266,9 @@ void dvb_unregister_device(struct dvb_device *dvbdev); #ifdef CONFIG_MEDIA_CONTROLLER_DVB /** * dvb_create_media_graph - Creates media graph for the Digital TV part of the - * device. + * device. * - * @adap: pointer to struct dvb_adapter + * @adap: pointer to &struct dvb_adapter * @create_rf_connector: if true, it creates the RF connector too * * This function checks all DVB-related functions at the media controller @@ -259,14 +281,25 @@ void dvb_unregister_device(struct dvb_device *dvbdev); __must_check int dvb_create_media_graph(struct dvb_adapter *adap, bool create_rf_connector); +/** + * dvb_register_media_controller - registers a media controller at DVB adapter + * + * @adap: pointer to &struct dvb_adapter + * @mdev: pointer to &struct media_device + */ static inline void dvb_register_media_controller(struct dvb_adapter *adap, struct media_device *mdev) { adap->mdev = mdev; } -static inline struct media_device -*dvb_get_media_controller(struct dvb_adapter *adap) +/** + * dvb_get_media_controller - gets the associated media controller + * + * @adap: pointer to &struct dvb_adapter + */ +static inline struct media_device * +dvb_get_media_controller(struct dvb_adapter *adap) { return adap->mdev; } @@ -281,20 +314,131 @@ int dvb_create_media_graph(struct dvb_adapter *adap, #define dvb_get_media_controller(a) NULL #endif -int dvb_generic_open (struct inode *inode, struct file *file); -int dvb_generic_release (struct inode *inode, struct file *file); -long dvb_generic_ioctl (struct file *file, - unsigned int cmd, unsigned long arg); +/** + * dvb_generic_open - Digital TV open function, used by DVB devices + * + * @inode: pointer to &struct inode. + * @file: pointer to &struct file. + * + * Checks if a DVB devnode is still valid, and if the permissions are + * OK and increment negative use count. + */ +int dvb_generic_open(struct inode *inode, struct file *file); -/* we don't mess with video_usercopy() any more, -we simply define out own dvb_usercopy(), which will hopefully become -generic_usercopy() someday... */ +/** + * dvb_generic_close - Digital TV close function, used by DVB devices + * + * @inode: pointer to &struct inode. + * @file: pointer to &struct file. + * + * Checks if a DVB devnode is still valid, and if the permissions are + * OK and decrement negative use count. + */ +int dvb_generic_release(struct inode *inode, struct file *file); +/** + * dvb_generic_ioctl - Digital TV close function, used by DVB devices + * + * @file: pointer to &struct file. + * @cmd: Ioctl name. + * @arg: Ioctl argument. + * + * Checks if a DVB devnode and struct dvbdev.kernel_ioctl is still valid. + * If so, calls dvb_usercopy(). + */ +long dvb_generic_ioctl(struct file *file, + unsigned int cmd, unsigned long arg); + +/** + * dvb_usercopy - copies data from/to userspace memory when an ioctl is + * issued. + * + * @file: Pointer to struct &file. + * @cmd: Ioctl name. + * @arg: Ioctl argument. + * @func: function that will actually handle the ioctl + * + * Ancillary function that uses ioctl direction and size to copy from + * userspace. Then, it calls @func, and, if needed, data is copied back + * to userspace. + */ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, int (*func)(struct file *file, unsigned int cmd, void *arg)); -/** generic DVB attach function. */ +#if IS_ENABLED(CONFIG_I2C) + +struct i2c_adapter; +struct i2c_client; +/** + * dvb_module_probe - helper routine to probe an I2C module + * + * @module_name: + * Name of the I2C module to be probed + * @name: + * Optional name for the I2C module. Used for debug purposes. + * If %NULL, defaults to @module_name. + * @adap: + * pointer to &struct i2c_adapter that describes the I2C adapter where + * the module will be bound. + * @addr: + * I2C address of the adapter, in 7-bit notation. + * @platform_data: + * Platform data to be passed to the I2C module probed. + * + * This function binds an I2C device into the DVB core. Should be used by + * all drivers that use I2C bus to control the hardware. A module bound + * with dvb_module_probe() should use dvb_module_release() to unbind. + * + * Return: + * On success, return an &struct i2c_client, pointing to the bound + * I2C device. %NULL otherwise. + * + * .. note:: + * + * In the past, DVB modules (mainly, frontends) were bound via dvb_attach() + * macro, with does an ugly hack, using I2C low level functions. Such + * usage is deprecated and will be removed soon. Instead, use this routine. + */ +struct i2c_client *dvb_module_probe(const char *module_name, + const char *name, + struct i2c_adapter *adap, + unsigned char addr, + void *platform_data); + +/** + * dvb_module_release - releases an I2C device allocated with + * dvb_module_probe(). + * + * @client: pointer to &struct i2c_client with the I2C client to be released. + * can be %NULL. + * + * This function should be used to free all resources reserved by + * dvb_module_probe() and unbinding the I2C hardware. + */ +void dvb_module_release(struct i2c_client *client); + +#endif /* CONFIG_I2C */ + +/* Legacy generic DVB attach function. */ #ifdef CONFIG_MEDIA_ATTACH +/** + * dvb_attach - attaches a DVB frontend into the DVB core. + * + * @FUNCTION: function on a frontend module to be called. + * @ARGS...: @FUNCTION arguments. + * + * This ancillary function loads a frontend module in runtime and runs + * the @FUNCTION function there, with @ARGS. + * As it increments symbol usage cont, at unregister, dvb_detach() + * should be called. + * + * .. note:: + * + * In the past, DVB modules (mainly, frontends) were bound via dvb_attach() + * macro, with does an ugly hack, using I2C low level functions. Such + * usage is deprecated and will be removed soon. Instead, you should use + * dvb_module_probe(). + */ #define dvb_attach(FUNCTION, ARGS...) ({ \ void *__r = NULL; \ typeof(&FUNCTION) __a = symbol_request(FUNCTION); \ @@ -308,6 +452,14 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, __r; \ }) +/** + * dvb_detach - detaches a DVB frontend loaded via dvb_attach() + * + * @FUNC: attach function + * + * Decrements usage count for a function previously called via dvb_attach(). + */ + #define dvb_detach(FUNC) symbol_put_addr(FUNC) #else @@ -317,6 +469,6 @@ int dvb_usercopy(struct file *file, unsigned int cmd, unsigned long arg, #define dvb_detach(FUNC) {} -#endif +#endif /* CONFIG_MEDIA_ATTACH */ #endif /* #ifndef _DVBDEV_H_ */ From 97a88de738fe4d838c53f308ee1b0596983ba4fa Mon Sep 17 00:00:00 2001 From: drmocm Date: Sat, 10 Oct 2020 17:32:56 +0200 Subject: [PATCH 40/55] add --pam (-a) option for IQ data output in pam format to stdout. Needs a number >0 as argument. --- lib/Makefile | 4 +- lib/ddzap.c | 201 +++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 198 insertions(+), 7 deletions(-) diff --git a/lib/Makefile b/lib/Makefile index ecc0981..8ed2eb7 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -13,10 +13,10 @@ install: all $(CC) $(CFLAGS) -fPIC -c $< dddvb_test: dddvb_test.o - $(CC) -o dddvb_test $< -L ./src -l dddvb -l pthread -l dvben50221 -l dvbapi -l ucsi + $(CC) -o dddvb_test $< -L ./src -l dddvb -l pthread -l dvben50221 -l dvbapi -l ucsi ddzap: ddzap.o - $(CC) -o ddzap $< -L ./src -l dddvb -l pthread -l dvben50221 -l dvbapi -l ucsi + $(CC) -o ddzap $< -L ./src -l dddvb -l pthread -l dvben50221 -l dvbapi -l ucsi -lm clean: make -C ./src clean diff --git a/lib/ddzap.c b/lib/ddzap.c index 519e8b8..cf29a41 100644 --- a/lib/ddzap.c +++ b/lib/ddzap.c @@ -10,6 +10,8 @@ #include #include #include +#include +#include char line_start[16] = ""; char line_end[16] = "\r"; @@ -22,6 +24,175 @@ uint32_t packet_errors = 0; uint8_t cc[8192] = { 0 }; +enum { IQ_RED=1, IQ_GREE, IQ_BLUE , IQ_EVIL, IQ_LOG_RED, IQ_LOG_GREEN, IQ_LOG_BLUE , IQ_LOG_EVIL , IQ_TEST, }; + +typedef struct pamdata_ +{ + unsigned char *data_points; + uint64_t *data; + int col; +} pamdata; + +int init_pamdata(pamdata *iq,int color) +{ + iq->col = 0; + if (!( iq->data=(uint64_t *) malloc(sizeof(uint64_t) *256*256))) + { + fprintf(stderr,"not enough memory\n"); + return -1; + } + memset(iq->data,0,256*256*sizeof(uint64_t)); + if (!( iq->data_points=(unsigned char *) malloc(sizeof(unsigned char) * + 256*256*3))) + { + fprintf(stderr,"not enough memory\n"); + return -1; + } + memset(iq->data_points,0,256*256*3*sizeof(char)); + iq->col = color; + return 0; +} + +static long getutime(){ + struct timespec t0; + clock_gettime(CLOCK_MONOTONIC_RAW,&t0); + return t0.tv_sec * (int)1e9 + t0.tv_nsec; +} + +void pam_coordinate_axes(pamdata *iq, unsigned char r, + unsigned char g, unsigned char b){ + int i; + for (i = 0; i < 256*3; i+=3){ + // coordinate axes + int xr = i + 256*128*3; + int yr =128*3 + i*256; + iq->data_points[xr] = r; + iq->data_points[yr] = r; + iq->data_points[xr+1] = g; + iq->data_points[yr+1] = g; + iq->data_points[xr+2] = b; + iq->data_points[yr+2] = b; + } + +} +void pam_data_convert(pamdata *iq ,uint64_t maxd) +{ + int i; + uint64_t m = 255*maxd; + double lm = log((double)m); + memset(iq->data_points,0,256*256*3*sizeof(char)); + for (i = 0; i < 256*256*3; i+=3){ + // IQ data plot + int r = i; + int g = i+1; + int b = i+2; + uint64_t odata = iq->data[i/3]; + uint64_t data = 255*iq->data[i/3]; + double lod = log((double)odata); + double q = lod/lm; + if (data){ + switch (iq->col){ + case IQ_LOG_EVIL: + if ( q < 0.25){ + iq->data_points[b] = (int)(1024.0*q); + } else { + if (q >0.5) iq->data_points[g] = (int)(255.0*q); + else + iq->data_points[r] = (int)(512.0*q); + } + break; + case IQ_LOG_RED: + iq->data_points[r] = (int)(255.0*q)&0xff; + break; + case IQ_LOG_GREEN: + iq->data_points[g] = (int)(255.0*q)&0xff; + break; + case IQ_LOG_BLUE: + iq->data_points[b] = (int)(255.0*q)&0xff; + break; + case IQ_EVIL: + if (data < m/4){ + iq->data_points[b] = ((4*data)/maxd)&0xff; + } else { + if (data >m/2) iq->data_points[g] = (data/maxd)&0xff; + else iq->data_points[r] = (2*data/maxd)&0xff; + } + break; + case IQ_TEST: + if (data < m/4){ + iq->data_points[b] = ((4*data)/maxd)&0xff; + iq->data_points[g] = ((4*data)/maxd)&0xff; + } else { + if (data >m/2) { + iq->data_points[g] = (data/maxd)&0xff; + } else { + iq->data_points[g] = (2*data/maxd)&0xff; + iq->data_points[r] = (2*data/maxd)&0xff; + } + } + break; + case IQ_RED: + iq->data_points[r] = (data/maxd)&0xff; + break; + case IQ_BLUE: + iq->data_points[b] = (data/maxd)&0xff; + break; + + default: + case IQ_GREE: + iq->data_points[g] = (data/maxd)&0xff; + break; + } + } + + } +} +#define TS_SIZE 188 +#define BSIZE 100*TS_SIZE +#define DTIME 40000000ULL +void pam_read_data (int fdin, pamdata *iq) +{ + int8_t buf[BSIZE]; + int i,j; + + long t0; + long t1; + uint64_t maxd = 0; + + t0 = getutime(); + t1 = t0; + + while ((t1 - t0) < DTIME){ + int re =0; + if ((re=read(fdin,(char *)buf, BSIZE)) < 0){ + return; + } + for (i=0; i < re; i+=TS_SIZE){ + for (j=4; jdata[ix|(qy<<8)] += 1; + uint64_t c = iq->data[ix|(qy<<8)]; + if ( c > maxd) maxd = c; + } + } + t1 = getutime(); + } + + pam_data_convert(iq, maxd); + pam_coordinate_axes(iq, 255,255 ,0); + memset(iq->data,0,256*256*sizeof(uint64_t)); +} + +void pam_write (int fd, pamdata *iq){ + char *HEAD="P7\nWIDTH 256\nHEIGHT 256\nDEPTH 3\nMAXVAL 255\nTUPLTYPE RGB\nENDHDR\n"; + int headlen = strlen(HEAD); + int we=0; + we=write(fd,HEAD,headlen); + we=write(fd,iq->data_points,256*256*3); + memset(iq->data_points,0,256*256*3*sizeof(char)); +} + void proc_ts(int i, uint8_t *buf) { uint16_t pid=0x1fff&((buf[1]<<8)|buf[2]); @@ -111,6 +282,9 @@ int main(int argc, char **argv) int odvr = 0; FILE *fout = stdout; int line = -1; + int color = 0; + pamdata iq; + while (1) { int cur_optind = optind ? optind : 1; @@ -134,16 +308,21 @@ 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'}, {"help", no_argument , 0, 'h'}, {0, 0, 0, 0} }; c = getopt_long(argc, argv, - "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:q", long_options, &option_index); if (c==-1) break; switch (c) { + case 'e': + odvr = 2; + color = strtoul(optarg, NULL, 0); + break; case 'o': fout = stderr; if (odvr) { @@ -352,10 +531,22 @@ int main(int argc, char **argv) if ((fd = open(filename ,O_RDONLY)) < 0){ fprintf(stderr,"Error opening input file:%s\n",filename); } - if (odvr == 1){ - while(1){ - read(fd,buf,BUFFSIZE); - write(fileno(stdout),buf,BUFFSIZE); + 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; } } else { if( line >= 0 && line < 64 ){ From 8e39e291a08e800773166d99bac281b1535037eb Mon Sep 17 00:00:00 2001 From: none Date: Thu, 17 Sep 2020 09:55:24 +0200 Subject: [PATCH 41/55] change to new function call --- apps/flashprog.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/apps/flashprog.c b/apps/flashprog.c index 841b72e..fdac041 100644 --- a/apps/flashprog.c +++ b/apps/flashprog.c @@ -72,6 +72,7 @@ int sure() int main(int argc, char **argv) { char ddbname[80]; + char *flashname; int type = 0; struct ddb_id ddbid; uint8_t *buffer; @@ -147,7 +148,7 @@ int main(int argc, char **argv) printf("Could not open device\n"); return -1; } - Flash = flashdetect(ddb, &SectorSize, &FlashSize); + Flash = flashdetect(ddb, &SectorSize, &FlashSize, &flashname); get_ddid(ddb, &ddbid); #if 0 From 072689735c557bc0f19bfbd285033ebc8d55db7d Mon Sep 17 00:00:00 2001 From: none Date: Thu, 17 Sep 2020 09:55:48 +0200 Subject: [PATCH 42/55] prevent memory fault from card name if file name is given --- apps/octonet/ddupdate.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/apps/octonet/ddupdate.c b/apps/octonet/ddupdate.c index 3faeeda..82a2b91 100644 --- a/apps/octonet/ddupdate.c +++ b/apps/octonet/ddupdate.c @@ -34,9 +34,9 @@ static int yesno() static int update_flash(struct ddflash *ddf) { - char *fname; + char *fname, *default_fname; int res, stat = 0; - char *name; + char *name = 0, *dname; switch (ddf->id.device) { case 0x300: @@ -111,8 +111,9 @@ static int update_flash(struct ddflash *ddf) break; default: fname = ddf->fname; + default_fname = devid2fname(ddf->id.device, &name); if (!fname) - fname = devid2fname(ddf->id.device, &name); + fname = default_fname; if (name) printf("Card: %s\n", name); if (ddf->flash_name) From 1b11064b83c2305478e492aa0219069f4c09fb79 Mon Sep 17 00:00:00 2001 From: none Date: Thu, 17 Sep 2020 09:56:34 +0200 Subject: [PATCH 43/55] let files be bigger --- apps/octonet/flash.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/apps/octonet/flash.c b/apps/octonet/flash.c index a71886f..adad2fc 100644 --- a/apps/octonet/flash.c +++ b/apps/octonet/flash.c @@ -996,10 +996,12 @@ 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) From b46b89d4b509e48bf2c7a9abd8387269f75a7bae Mon Sep 17 00:00:00 2001 From: none Date: Thu, 17 Sep 2020 09:57:45 +0200 Subject: [PATCH 44/55] return no modulation for DVB-S2X modes, no defines available in LINUX API yet --- ddbridge/ddbridge-mci.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/ddbridge/ddbridge-mci.c b/ddbridge/ddbridge-mci.c index 66ad2f5..b617064 100644 --- a/ddbridge/ddbridge-mci.c +++ b/ddbridge/ddbridge-mci.c @@ -267,15 +267,25 @@ void ddb_mci_proc_info(struct mci *mci, struct dtv_frontend_properties *p) (mci->signal_info.dvbs2_signal_info.standard == 2) ? SYS_DVBS2 : SYS_DVBS; if (mci->signal_info.dvbs2_signal_info.standard == 2) { - u32 modcod = (0x7c & pls_code) >> 2; + u32 modcod; p->delivery_system = SYS_DVBS2; + p->transmission_mode = pls_code; p->rolloff = ro_lut[mci->signal_info.dvbs2_signal_info.roll_off & 7]; p->pilot = (pls_code & 1) ? PILOT_ON : PILOT_OFF; - p->fec_inner = modcod2fec[modcod]; - p->modulation = modcod2mod[modcod]; - p->transmission_mode = pls_code; + if (pls_code & 0x80) { + /* no suitable values defined in Linux DVB API yet */ + /* modcod = (0x7f & pls_code) >> 1; */ + p->fec_inner = FEC_NONE; + p->modulation = 0; + if (pls_code >= 250) + p->pilot = PILOT_ON; + } else { + modcod = (0x7c & pls_code) >> 2; + p->fec_inner = modcod2fec[modcod]; + p->modulation = modcod2mod[modcod]; + } } else { p->delivery_system = SYS_DVBS; p->rolloff = ROLLOFF_35; From d808f1d37ad6528495f59279026e842698f58e5d Mon Sep 17 00:00:00 2001 From: none Date: Thu, 17 Sep 2020 09:59:43 +0200 Subject: [PATCH 45/55] wrong kernel version cheked --- dvb-core/dvbdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dvb-core/dvbdev.c b/dvb-core/dvbdev.c index d4bf829..26ab1b7 100644 --- a/dvb-core/dvbdev.c +++ b/dvb-core/dvbdev.c @@ -980,7 +980,7 @@ out: EXPORT_SYMBOL(dvb_usercopy); #if IS_ENABLED(CONFIG_I2C) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(4,3,0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,3,0)) struct i2c_client *dvb_module_probe(const char *module_name, const char *name, struct i2c_adapter *adap, From 16909b37a0b65f20716ba6dbd6ae8b35e82a0228 Mon Sep 17 00:00:00 2001 From: none Date: Thu, 17 Sep 2020 09:59:58 +0200 Subject: [PATCH 46/55] get PLS code and show as debug message --- lib/src/dddvb.h | 1 + lib/src/dvb_quality.c | 3 +++ 2 files changed, 4 insertions(+) diff --git a/lib/src/dddvb.h b/lib/src/dddvb.h index f9e76d8..4f2390f 100644 --- a/lib/src/dddvb.h +++ b/lib/src/dddvb.h @@ -75,6 +75,7 @@ struct dddvb_fe { uint32_t level; uint32_t lock; uint32_t quality; + uint32_t pls_code; int64_t strength; int64_t cnr; int64_t ber; diff --git a/lib/src/dvb_quality.c b/lib/src/dvb_quality.c index f9bc86a..ecef831 100644 --- a/lib/src/dvb_quality.c +++ b/lib/src/dvb_quality.c @@ -331,6 +331,9 @@ static void calc_lq(struct dddvb_fe *fe) int64_t str, snr; uint32_t mod, fec, ber_num, ber_den, trans, pilot = 0, quality = 0; + get_property(fe->fd, DTV_TRANSMISSION_MODE, &fe->pls_code); + dbgprintf(DEBUG_DVB, "fe%d: pls=0x%02x\n", fe->nr, fe->pls_code); + get_stat(fe->fd, DTV_STAT_SIGNAL_STRENGTH, &st); str = st.stat[0].svalue; dbgprintf(DEBUG_DVB, "fe%d: str=%lld\n", fe->nr, str); From 527f6a47a3c74ed370384a6584fe2d8151a7e66f Mon Sep 17 00:00:00 2001 From: rjkm Date: Fri, 16 Oct 2020 14:28:05 +0200 Subject: [PATCH 47/55] adapt to latest upstream header file --- ddbridge/ddbridge-mci.h | 27 +++++++++++++++++++++++---- 1 file changed, 23 insertions(+), 4 deletions(-) diff --git a/ddbridge/ddbridge-mci.h b/ddbridge/ddbridge-mci.h index 8ed3a58..2fe37bc 100644 --- a/ddbridge/ddbridge-mci.h +++ b/ddbridge/ddbridge-mci.h @@ -148,11 +148,12 @@ #define M4_CMD_GET_IDS (0x51) #define M4_CMD_GET_DVBT_TPS (0x52) #define MCI_CMD_GET_BBHEADER (0x53) -#define M4_CMD_GET_BBHEADER (MCI_CMD_GET_BBHEADER) #define M4_CMD_GET_ISDBT_TMCC (0x54) #define M4_CMD_GET_ISDBS_TMCC (0x55) #define M4_CMD_GET_ISDBC_TSMF (0x56) +#define M4_CMD_GET_BBHEADER (MCI_CMD_GET_BBHEADER) + #define M4_L1INFO_SEL_PRE (0) #define M4_L1INFO_SEL_DSINFO (1) #define M4_L1INFO_SEL_PLPINFO (2) @@ -180,6 +181,7 @@ #define M4_SIGNALINFO_FLAG_CHANGE (0x01) #define M4_SIGNALINFO_FLAG_EWS (0x02) +#define SX8_ROLLOFF_35 0 #define SX8_ROLLOFF_25 1 #define SX8_ROLLOFF_20 2 #define SX8_ROLLOFF_15 5 @@ -205,7 +207,7 @@ struct mci_command { u32 params[31]; struct { u8 flags; /* Bit 0: DVB-S Enabled, 1: DVB-S2 Enabled, - 6: FrequencyRange, 7: InputStreamID */ + 5: ChannelBonding, 6: FrequencyRange, 7: InputStreamID */ u8 s2_modulation_mask; /* Bit 0 : QPSK, 1: 8PSK/8APSK, 2 : 16APSK, 3: 32APSK, 4: 64APSK, 5: 128APSK, 6: 256APSK */ @@ -217,6 +219,9 @@ struct mci_command { u8 rsvd2[3]; u32 scrambling_sequence_index; u32 frequency_range; + u8 channel_bonding_config; /* Bit 7: IsSlave, Bit 5..4: MasterDemod, + bit 0: Num channels - 2. + (must be set on all channels to same value) */ } dvbs2_search; struct { @@ -306,7 +311,6 @@ struct mci_command { u16 point; } get_iq_symbol; - struct { uint8_t flags; /* Bit 0 : 0 = VTM/SDR, 1 = SCAN, Bit 1: 1 = Disable AGC, @@ -319,7 +323,7 @@ struct mci_command { uint8_t 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) , @@ -393,6 +397,21 @@ struct mci_result { u32 ber_denominator; } dvbs2_signal_info; + struct { + u8 modcod; + u8 rsvd0[2]; + u8 flags; /* Bit 0: TMCC changed, Bit 1: EWS */ + u32 frequency; /* actual frequency in Hz */ + u32 symbol_rate; /* actual symbolrate in Hz */ + s16 channel_power; /* channel power in dBm x 100 */ + s16 band_power; /*/ band power in dBm x 100 */ + s16 signal_to_noise; /* SNR in dB x 100, Note: negativ values are valid in DVB-S2 */ + s16 rsvd2; + u32 packet_errors; /* Counter for packet errors. (set to 0 on Start command) */ + u32 ber_numerator; /* Bit error rate: PreRS in DVB-S, PreBCH in DVB-S2X */ + u32 ber_denominator; + } isdbs_signal_info; + struct { u8 constellation; u8 rsvd0[2]; From b60efcdaad94a4fd232e8e597b7b63c6506a6529 Mon Sep 17 00:00:00 2001 From: rjkm Date: Fri, 16 Oct 2020 14:28:55 +0200 Subject: [PATCH 48/55] fix j83b tuning --- lib/src/dvb.c | 38 +++++++++++++++++++++++++------------- 1 file changed, 25 insertions(+), 13 deletions(-) diff --git a/lib/src/dvb.c b/lib/src/dvb.c index 81a1ef7..72e9703 100644 --- a/lib/src/dvb.c +++ b/lib/src/dvb.c @@ -332,7 +332,7 @@ static int tune_c(struct dddvb_fe *fe) { struct dtv_property p[] = { { .cmd = DTV_CLEAR }, - { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] }, + { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000}, { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ? fe->param.param[PARAM_BW_HZ] : 8000000 }, { .cmd = DTV_SYMBOL_RATE, .u.data = fe->param.param[PARAM_SR] }, @@ -359,19 +359,28 @@ static int tune_c(struct dddvb_fe *fe) return 0; } -static int tune_cable(struct dddvb_fe *fe) +static int tune_j83b(struct dddvb_fe *fe) { - uint32_t freq; - struct dvb_frontend_parameters p = { - .frequency = fe->param.param[PARAM_FREQ] * 1000, - .u.qam.symbol_rate = fe->param.param[PARAM_SR], - .u.qam.fec_inner = (fe->param.param[PARAM_FEC] != DDDVB_UNDEF) ? - (fe->param.param[PARAM_FEC]) : FEC_AUTO, - .u.qam.modulation = fe->param.param[PARAM_MTYPE], - }; - set_property(fe->fd, DTV_DELIVERY_SYSTEM, SYS_DVBC_ANNEX_A); - if (ioctl(fe->fd, FE_SET_FRONTEND, &p) == -1) { - perror("FE_SET_FRONTEND error"); + struct dtv_property p[] = { + { .cmd = DTV_CLEAR }, + { .cmd = DTV_FREQUENCY, .u.data = fe->param.param[PARAM_FREQ] * 1000}, + { .cmd = DTV_BANDWIDTH_HZ, .u.data = (fe->param.param[PARAM_BW_HZ] != DDDVB_UNDEF) ? + fe->param.param[PARAM_BW_HZ] : 6000000 }, + { .cmd = DTV_SYMBOL_RATE, .u.data = (fe->param.param[PARAM_SR] != DDDVB_UNDEF) ? + fe->param.param[PARAM_SR] : 5056941}, + { .cmd = DTV_TUNE }, + }; + struct dtv_properties c; + int ret; + + printf("tune_j83b()\n"); + set_property(fe->fd, DTV_DELIVERY_SYSTEM, SYS_DVBC_ANNEX_B); + + c.num = ARRAY_SIZE(p); + c.props = p; + ret = ioctl(fe->fd, FE_SET_PROPERTY, &c); + if (ret < 0) { + fprintf(stderr, "FE_SET_PROPERTY returned %d\n", ret); return -1; } return 0; @@ -513,6 +522,9 @@ static int tune(struct dddvb_fe *fe) case SYS_DVBC_ANNEX_A: ret = tune_c(fe); break; + case SYS_DVBC_ANNEX_B: + ret = tune_j83b(fe); + break; case SYS_DVBT: ret = tune_terr(fe); break; From e0e9b82f5a1f9adb2bcea9b465a45114f44e870a Mon Sep 17 00:00:00 2001 From: rjkm Date: Fri, 16 Oct 2020 14:30:38 +0200 Subject: [PATCH 49/55] add link to mci_base to ddb_link --- ddbridge/ddbridge.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ddbridge/ddbridge.h b/ddbridge/ddbridge.h index 4ee5252..9170dfc 100644 --- a/ddbridge/ddbridge.h +++ b/ddbridge/ddbridge.h @@ -425,6 +425,8 @@ struct ddb_link { int over_temperature_error; u8 temp_tab[11]; struct ddb_irq irq[256]; + + struct mci_base *mci_base; }; struct ddb { From a375cd1716c65290c3a4aab49e8ea90d27c0940a Mon Sep 17 00:00:00 2001 From: rjkm Date: Fri, 16 Oct 2020 14:32:13 +0200 Subject: [PATCH 50/55] remove debug mesage --- ddbridge/ddbridge-sx8.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ddbridge/ddbridge-sx8.c b/ddbridge/ddbridge-sx8.c index d3bc223..3566d54 100644 --- a/ddbridge/ddbridge-sx8.c +++ b/ddbridge/ddbridge-sx8.c @@ -435,7 +435,6 @@ static int set_parameters(struct dvb_frontend *fe) ts_mode = (isi & 0x03000000) >> 24; } state->mci.input->con = ts_mode << 8; - printk("ts_mode = %02x\n", ts_mode); if (iq_mode) ts_config = (SX8_TSCONFIG_TSHEADER | SX8_TSCONFIG_MODE_IQ); stop(fe); From 22475860d55acd27e1599333b80e91cb807e6a6f Mon Sep 17 00:00:00 2001 From: rjkm Date: Fri, 16 Oct 2020 14:32:47 +0200 Subject: [PATCH 51/55] adjust kernel version check --- dvb-core/dvbdev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dvb-core/dvbdev.c b/dvb-core/dvbdev.c index 26ab1b7..6a991a6 100644 --- a/dvb-core/dvbdev.c +++ b/dvb-core/dvbdev.c @@ -980,7 +980,7 @@ out: EXPORT_SYMBOL(dvb_usercopy); #if IS_ENABLED(CONFIG_I2C) -#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,3,0)) +#if (LINUX_VERSION_CODE >= KERNEL_VERSION(5,5,0)) struct i2c_client *dvb_module_probe(const char *module_name, const char *name, struct i2c_adapter *adap, From 310a5e0f05f57e591ba9700f44989b6223df1d1f Mon Sep 17 00:00:00 2001 From: rjkm Date: Fri, 16 Oct 2020 14:33:27 +0200 Subject: [PATCH 52/55] add some symbol rate modes --- ddbridge/ddbridge-modulator.c | 38 +++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/ddbridge/ddbridge-modulator.c b/ddbridge/ddbridge-modulator.c index e532bd5..cf12a8a 100644 --- a/ddbridge/ddbridge-modulator.c +++ b/ddbridge/ddbridge-modulator.c @@ -1516,12 +1516,12 @@ static int mod3_set_ari(struct ddb_mod *mod, u32 rate) static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate) { - u32 cic, inc; - + u32 cic, inc, bypass = 0; + switch (rate) { /* 2^31 * freq*4*cic / 245.76Mhz */ case SYS_DVBT_6: - inc = 1917396114; + inc = 0x72492492; cic = 8; break; case SYS_DVBT_7: @@ -1533,19 +1533,45 @@ static int mod3_set_sample_rate(struct ddb_mod *mod, u32 rate) inc = 1917396114; cic = 6; break; + case SYS_DVBC_6900: + inc = 0x73000000; //1929379840; + cic = 8; + break; + case 9: + inc = 0x47e00000; //1929379840; + cic = 10; + bypass = 2; + break; + + case SYS_J83B_64_6: /* 5056941 */ + inc = 0x695a5a1d; + cic = 10; + break; + case SYS_J83B_256_6: /* 5360537 */ + inc = 0x6fad87da; + cic = 10; + break; + case SYS_ISDBT_6: - inc = 1988410754; + inc = 0x7684BD82; //1988410754; cic = 7; break; case SYS_DVBS2_22: - inc = 1922389333; + inc = 0x72955555; // 1922389333; cic = 5; + bypass = 2; + break; + case SYS_DVBS2_24: + inc = 0x7d000000; + cic = 5; + bypass = 2; break; default: return -EINVAL; } ddbwritel(mod->port->dev, inc, SDR_CHANNEL_ARICW(mod->port->nr)); - ddbwritel(mod->port->dev, cic << 8, SDR_CHANNEL_CONFIG(mod->port->nr)); + ddbwritel(mod->port->dev, (cic << 8) | (bypass << 4), + SDR_CHANNEL_CONFIG(mod->port->nr)); return 0; } From c93f96b6ec388f79d0441e6f8b7e3eeadafe0ec9 Mon Sep 17 00:00:00 2001 From: rjkm Date: Fri, 16 Oct 2020 14:33:55 +0200 Subject: [PATCH 53/55] add some symbol rate modes --- include/linux/dvb/mod.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/dvb/mod.h b/include/linux/dvb/mod.h index 3c1d5e4..196c481 100644 --- a/include/linux/dvb/mod.h +++ b/include/linux/dvb/mod.h @@ -38,10 +38,14 @@ struct dvb_mod_channel_params { enum mod_output_rate { SYS_DVBT_6 = 0, - SYS_DVBT_7, - SYS_DVBT_8, + SYS_DVBT_7 = 1, + SYS_DVBT_8 = 2, + SYS_DVBC_6900 = 8, SYS_ISDBT_6 = 16, + SYS_J83B_64_6 = 24, + SYS_J83B_256_6 = 25, SYS_DVBS2_22 = 32, + SYS_DVBS2_24 = 33, }; From 55aec3cf72e1d00460cd85457261ee60640de972 Mon Sep 17 00:00:00 2001 From: rjkm Date: Fri, 16 Oct 2020 14:36:25 +0200 Subject: [PATCH 54/55] remove unneeded include --- ddbridge/ddbridge-m4.c | 1 - 1 file changed, 1 deletion(-) diff --git a/ddbridge/ddbridge-m4.c b/ddbridge/ddbridge-m4.c index 1b29312..661ede4 100644 --- a/ddbridge/ddbridge-m4.c +++ b/ddbridge/ddbridge-m4.c @@ -24,7 +24,6 @@ #include "ddbridge.h" #include "ddbridge-io.h" -#include "ddbridge-i2c.h" #include "ddbridge-mci.h" struct m4_base { From d2e6c9b2cba35371c177bedb81e02fd5dc86ab1c Mon Sep 17 00:00:00 2001 From: rjkm Date: Fri, 16 Oct 2020 14:37:25 +0200 Subject: [PATCH 55/55] add fallback --- ddbridge/ddbridge-hw.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ddbridge/ddbridge-hw.c b/ddbridge/ddbridge-hw.c index af34a1e..083eff8 100644 --- a/ddbridge/ddbridge-hw.c +++ b/ddbridge/ddbridge-hw.c @@ -821,6 +821,8 @@ static const struct ddb_device_id ddb_device_ids[] = { DDB_DEVID(0x0323, 0xffff, ddb_none), DDB_DEVID(0x0328, 0xffff, ddb_none), DDB_DEVID(0x0329, 0xffff, ddb_octopro_hdin), + + DDB_DEVID(0xffff, 0xffff, ddb_none), }; const struct ddb_info *get_ddb_info(u16 vendor, u16 device, @@ -833,7 +835,8 @@ const struct ddb_info *get_ddb_info(u16 vendor, u16 device, if (vendor == id->vendor && device == id->device && - subvendor == id->subvendor && + (subvendor == id->subvendor || + id->subvendor == 0xffff) && (subdevice == id->subdevice || id->subdevice == 0xffff)) return id->info;