From: Mauro Carvalho Chehab <mchehab@kernel.org>
To: "Daniel W. S. Almeida" <dwlsalmeida@gmail.com>
Cc: sean@mess.org, kstewart@linuxfoundation.org, allison@lohutok.net,
tglx@linutronix.de, linux-media@vger.kernel.org,
skhan@linuxfoundation.org,
linux-kernel-mentees@lists.linuxfoundation.org
Subject: Re: [RFC, WIP, v2 2/3] media: dvb_dummy_fe.c: lose TS lock on bad snr
Date: Fri, 27 Mar 2020 16:51:56 +0100 [thread overview]
Message-ID: <20200327165156.055b256f@coco.lan> (raw)
In-Reply-To: <20200323125732.281976-3-dwlsalmeida@gmail.com>
Em Mon, 23 Mar 2020 09:57:31 -0300
"Daniel W. S. Almeida" <dwlsalmeida@gmail.com> escreveu:
> From: "Daniel W. S. Almeida" <dwlsalmeida@gmail.com>
>
> Periodically check the signal quality and eventually lose the lock if
> the quality is sub-par. A fake tuner can return a bad quality signal to
> the demod if the frequency is too far off from a valid frequency.
>
> Signed-off-by: Daniel W. S. Almeida <dwlsalmeida@gmail.com>
> ---
> drivers/media/dvb-frontends/dvb_dummy_fe.c | 160 ++++++++++++++++++++-
> 1 file changed, 155 insertions(+), 5 deletions(-)
>
> diff --git a/drivers/media/dvb-frontends/dvb_dummy_fe.c b/drivers/media/dvb-frontends/dvb_dummy_fe.c
> index 9ff1ebaa5e04..14446f2bdcde 100644
> --- a/drivers/media/dvb-frontends/dvb_dummy_fe.c
> +++ b/drivers/media/dvb-frontends/dvb_dummy_fe.c
> @@ -9,24 +9,166 @@
> #include <linux/init.h>
> #include <linux/string.h>
> #include <linux/slab.h>
> +#include <linux/workqueue.h>
> +#include <linux/random.h>
>
> #include <media/dvb_frontend.h>
> #include "dvb_dummy_fe.h"
>
>
> +struct dvb_dummy_fe_cnr_to_qual_s {
> + /* attempt to use the same values as libdvbv5 */
> + u32 modulation;
> + u32 fec;
> + u32 cnr_ok, cnr_good;
> +};
> +
> +struct dvb_dummy_fe_cnr_to_qual_s dvb_dummy_fe_c_cnr_2_qual[] = {
> + /* from libdvbv5 source code, in milli db */
> + { QAM_256, FEC_NONE, 34000, 38000},
> + { QAM_64, FEC_NONE, 30000, 34000},
> +};
> +
> +struct dvb_dummy_fe_cnr_to_qual_s dvb_dummy_fe_s_cnr_2_qual[] = {
> + /* from libdvbv5 source code, in milli db */
> + { QPSK, FEC_1_2, 7000, 10000},
> + { QPSK, FEC_2_3, 9000, 12000},
> + { QPSK, FEC_3_4, 10000, 13000},
> + { QPSK, FEC_5_6, 11000, 14000},
> + { QPSK, FEC_7_8, 12000, 15000},
> +};
> +
> +struct dvb_dummy_fe_cnr_to_qual_s dvb_dummy_fe_s2_cnr_2_qual[] = {
> + /* from libdvbv5 source code, in milli db */
> + { QPSK, FEC_1_2, 9000, 12000},
> + { QPSK, FEC_2_3, 11000, 14000},
> + { QPSK, FEC_3_4, 12000, 15000},
> + { QPSK, FEC_5_6, 12000, 15000},
> + { QPSK, FEC_8_9, 13000, 16000},
> + { QPSK, FEC_9_10, 13500, 16500},
> + { PSK_8, FEC_2_3, 14500, 17500},
> + { PSK_8, FEC_3_4, 16000, 19000},
> + { PSK_8, FEC_5_6, 17500, 20500},
> + { PSK_8, FEC_8_9, 19000, 22000},
> +};
> +
> +static struct dvb_dummy_fe_cnr_to_qual_s dvb_dummy_fe_t_cnr_2_qual[] = {
> + /* from libdvbv5 source code, in milli db*/
> + { QPSK, FEC_1_2, 4100, 5900},
> + { QPSK, FEC_2_3, 6100, 9600},
> + { QPSK, FEC_3_4, 7200, 12400},
> + { QPSK, FEC_5_6, 8500, 15600},
> + { QPSK, FEC_7_8, 9200, 17500},
> +
> + { QAM_16, FEC_1_2, 9800, 11800},
> + { QAM_16, FEC_2_3, 12100, 15300},
> + { QAM_16, FEC_3_4, 13400, 18100},
> + { QAM_16, FEC_5_6, 14800, 21300},
> + { QAM_16, FEC_7_8, 15700, 23600},
> +
> + { QAM_64, FEC_1_2, 14000, 16000},
> + { QAM_64, FEC_2_3, 19900, 25400},
> + { QAM_64, FEC_3_4, 24900, 27900},
> + { QAM_64, FEC_5_6, 21300, 23300},
> + { QAM_64, FEC_7_8, 22000, 24000},
> +};
> +
> +struct dvb_dummy_fe_config {
> + /* probability of losing the lock due to low snr */
> + u8 drop_tslock_prob_on_low_snr;
> + u8 recover_tslock_prob_on_good_snr;
> +};
> +
> struct dvb_dummy_fe_state {
> struct dvb_frontend frontend;
> + struct dvb_dummy_fe_config config;
> + struct delayed_work poll_snr;
> + enum fe_status status;
> };
>
> +static void poll_snr_handler(struct work_struct *work)
> +{
> + /*
> + * periodically check the signal quality and eventually
> + * lose the TS lock if it dips too low
> + */
> + struct dvb_dummy_fe_state *state;
> + struct dtv_frontend_properties *c;
> + struct dvb_dummy_fe_cnr_to_qual_s *cnr2qual = NULL;
> + struct dvb_dummy_fe_config *config;
> + u32 array_size = 0;
> + u16 snr = 0;
> + u32 i;
> +
> + state = container_of(work, struct dvb_dummy_fe_state, poll_snr.work);
> + c = &state->frontend.dtv_property_cache;
> + config = &state->config;
> +
> + if (!state->frontend.ops.tuner_ops.get_rf_strength)
> + return;
> +
> + state->frontend.ops.tuner_ops.get_rf_strength(&state->frontend, &snr);
> +
> + switch (c->delivery_system) {
> + case SYS_DVBT:
> + case SYS_DVBT2:
> + cnr2qual = dvb_dummy_fe_t_cnr_2_qual;
> + array_size = ARRAY_SIZE(dvb_dummy_fe_t_cnr_2_qual);
> + break;
> +
> + case SYS_DVBS:
> + cnr2qual = dvb_dummy_fe_s_cnr_2_qual;
> + array_size = ARRAY_SIZE(dvb_dummy_fe_s_cnr_2_qual);
> + break;
> +
> + case SYS_DVBS2:
> + cnr2qual = dvb_dummy_fe_s2_cnr_2_qual;
> + array_size = ARRAY_SIZE(dvb_dummy_fe_s2_cnr_2_qual);
> + break;
> +
> + case SYS_DVBC_ANNEX_A:
> + cnr2qual = dvb_dummy_fe_c_cnr_2_qual;
> + array_size = ARRAY_SIZE(dvb_dummy_fe_c_cnr_2_qual);
> + break;
> +
> + default:
> + pr_warn("%This is missing one important case:
s: unsupported delivery system: %u\n",
> + __func__,
> + c->delivery_system);
> + break;
> + }
> +
The loop below is missing one important case: tuner is at completely
wrong frequency (e. g. when signal strength is 0).
Ok, ideally, the thread shouldn't even be running on such cases,
but, from your code, you're starting the thread when the driver is
initialized. So, a test like this would be needed here.
Well, I would actually do it on a different way, but then you'll need
to add more logic:
- store the CNR returned by the tuner after calls to set_frontend;
- if the stored CNR is -1, don't run the &state->poll_snr;
- if the stored CNR is between "ok" and "good" (e. g. frequency
shift is zero), don't run this tread. Just fill the signal
as if the channel is tunned;
- Otherwise, run this thread.
- At suspend, stop the thread only if it was running before;
- At resume, start the thread only if it was suspended with the
thread running. Extra care should be taken here, as some tuner
status change might happen at resume time (for example, due to
a ioctl syscall to set_frontend, or due to a release syscall).
> + for (i = 0; i <= array_size; i++) {
> + if (cnr2qual[i].modulation == c->modulation &&
> + cnr2qual[i].fec == c->fec_inner) {
> + if (snr < cnr2qual[i].cnr_ok) {
> + /* eventually lose the TS lock */
> + if (prandom_u32_max(100) <
> + config->drop_tslock_prob_on_low_snr)
> + state->status = 0;
> + } else {
> + /* recover if the signal improves */
> + if (prandom_u32_max(100) <
> + config->recover_tslock_prob_on_good_snr)
> + state->status = FE_HAS_SIGNAL |
> + FE_HAS_CARRIER |
> + FE_HAS_VITERBI |
> + FE_HAS_SYNC |
> + FE_HAS_LOCK;
> + }
Please add a:
break;
as, once you get the right modulation/fec, there's no need to look up
further.
> + }
> + }
> +
> + schedule_delayed_work(&state->poll_snr, msecs_to_jiffies(2000));
> +}
>
> static int dvb_dummy_fe_read_status(struct dvb_frontend *fe,
> enum fe_status *status)
> {
> - *status = FE_HAS_SIGNAL
> - | FE_HAS_CARRIER
> - | FE_HAS_VITERBI
> - | FE_HAS_SYNC
> - | FE_HAS_LOCK;
> +
> + struct dvb_dummy_fe_state *state = fe->demodulator_priv;
> +
> + *status = state->status;
>
> return 0;
> }
> @@ -80,11 +222,18 @@ static int dvb_dummy_fe_set_frontend(struct dvb_frontend *fe)
>
> static int dvb_dummy_fe_sleep(struct dvb_frontend *fe)
> {
> + struct dvb_dummy_fe_state *state = fe->demodulator_priv;
> +
> + cancel_delayed_work_sync(&state->poll_snr);
> return 0;
> }
>
> static int dvb_dummy_fe_init(struct dvb_frontend *fe)
> {
> + struct dvb_dummy_fe_state *state = fe->demodulator_priv;
> +
> + INIT_DELAYED_WORK(&state->poll_snr, &poll_snr_handler);
> + schedule_delayed_work(&state->poll_snr, msecs_to_jiffies(2000));
> return 0;
> }
>
> @@ -104,6 +253,7 @@ static void dvb_dummy_fe_release(struct dvb_frontend *fe)
> {
> struct dvb_dummy_fe_state *state = fe->demodulator_priv;
>
> + cancel_delayed_work_sync(&state->poll_snr);
> kfree(state);
> }
>
Thanks,
Mauro
next prev parent reply other threads:[~2020-03-27 15:52 UTC|newest]
Thread overview: 10+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-03-23 12:57 [RFC, WIP, v2 0/3] Implement a virtual DVB driver Daniel W. S. Almeida
2020-03-23 12:57 ` [RFC, WIP, v2 1/3] media: dvb_dummy_tuner: implement driver skeleton Daniel W. S. Almeida
2020-03-27 15:30 ` Mauro Carvalho Chehab
2020-03-29 10:09 ` Sean Young
2020-03-23 12:57 ` [RFC, WIP, v2 2/3] media: dvb_dummy_fe.c: lose TS lock on bad snr Daniel W. S. Almeida
2020-03-27 15:51 ` Mauro Carvalho Chehab [this message]
2020-03-23 12:57 ` [RFC, WIP, v2 3/3] media: dvb_dummy_fe.c: write PSI information into DMX buffer Daniel W. S. Almeida
2020-03-27 16:48 ` Mauro Carvalho Chehab
[not found] ` <a4066f72-ae83-c1ef-8bf7-d4bbcfa29b31@gmail.com>
2020-03-27 19:23 ` Daniel W. S. Almeida
2020-03-27 19:56 ` Mauro Carvalho Chehab
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200327165156.055b256f@coco.lan \
--to=mchehab@kernel.org \
--cc=allison@lohutok.net \
--cc=dwlsalmeida@gmail.com \
--cc=kstewart@linuxfoundation.org \
--cc=linux-kernel-mentees@lists.linuxfoundation.org \
--cc=linux-media@vger.kernel.org \
--cc=sean@mess.org \
--cc=skhan@linuxfoundation.org \
--cc=tglx@linutronix.de \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).