cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

vidtv_demod.c (12317B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * The Virtual DVB test driver serves as a reference DVB driver and helps
      4 * validate the existing APIs in the media subsystem. It can also aid
      5 * developers working on userspace applications.
      6 *
      7 * Copyright (C) 2020 Daniel W. S. Almeida
      8 * Based on the example driver written by Emard <emard@softhome.net>
      9 */
     10
     11#include <linux/errno.h>
     12#include <linux/i2c.h>
     13#include <linux/init.h>
     14#include <linux/kernel.h>
     15#include <linux/module.h>
     16#include <linux/printk.h>
     17#include <linux/random.h>
     18#include <linux/ratelimit.h>
     19#include <linux/slab.h>
     20#include <linux/string.h>
     21#include <linux/workqueue.h>
     22
     23#include <media/dvb_frontend.h>
     24
     25#include "vidtv_demod.h"
     26
     27#define POLL_THRD_TIME 2000 /* ms */
     28
     29static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_c_cnr_2_qual[] = {
     30	/* from libdvbv5 source code, in milli db */
     31	{ QAM_256, FEC_NONE,  34000, 38000},
     32	{ QAM_64,  FEC_NONE,  30000, 34000},
     33};
     34
     35static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_s_cnr_2_qual[] = {
     36	/* from libdvbv5 source code, in milli db */
     37	{ QPSK, FEC_1_2,  7000, 10000},
     38	{ QPSK, FEC_2_3,  9000, 12000},
     39	{ QPSK, FEC_3_4, 10000, 13000},
     40	{ QPSK, FEC_5_6, 11000, 14000},
     41	{ QPSK, FEC_7_8, 12000, 15000},
     42};
     43
     44static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_s2_cnr_2_qual[] = {
     45	/* from libdvbv5 source code, in milli db */
     46	{ QPSK,  FEC_1_2,   9000,  12000},
     47	{ QPSK,  FEC_2_3,  11000,  14000},
     48	{ QPSK,  FEC_3_4,  12000,  15000},
     49	{ QPSK,  FEC_5_6,  12000,  15000},
     50	{ QPSK,  FEC_8_9,  13000,  16000},
     51	{ QPSK,  FEC_9_10, 13500,  16500},
     52	{ PSK_8, FEC_2_3,  14500,  17500},
     53	{ PSK_8, FEC_3_4,  16000,  19000},
     54	{ PSK_8, FEC_5_6,  17500,  20500},
     55	{ PSK_8, FEC_8_9,  19000,  22000},
     56};
     57
     58static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_t_cnr_2_qual[] = {
     59	/* from libdvbv5 source code, in milli db*/
     60	{   QPSK, FEC_1_2,  4100,  5900},
     61	{   QPSK, FEC_2_3,  6100,  9600},
     62	{   QPSK, FEC_3_4,  7200, 12400},
     63	{   QPSK, FEC_5_6,  8500, 15600},
     64	{   QPSK, FEC_7_8,  9200, 17500},
     65	{ QAM_16, FEC_1_2,  9800, 11800},
     66	{ QAM_16, FEC_2_3, 12100, 15300},
     67	{ QAM_16, FEC_3_4, 13400, 18100},
     68	{ QAM_16, FEC_5_6, 14800, 21300},
     69	{ QAM_16, FEC_7_8, 15700, 23600},
     70	{ QAM_64, FEC_1_2, 14000, 16000},
     71	{ QAM_64, FEC_2_3, 19900, 25400},
     72	{ QAM_64, FEC_3_4, 24900, 27900},
     73	{ QAM_64, FEC_5_6, 21300, 23300},
     74	{ QAM_64, FEC_7_8, 22000, 24000},
     75};
     76
     77static const struct vidtv_demod_cnr_to_qual_s *vidtv_match_cnr_s(struct dvb_frontend *fe)
     78{
     79	const struct vidtv_demod_cnr_to_qual_s *cnr2qual = NULL;
     80	struct device *dev = fe->dvb->device;
     81	struct dtv_frontend_properties *c;
     82	u32 array_size = 0;
     83	u32 i;
     84
     85	c = &fe->dtv_property_cache;
     86
     87	switch (c->delivery_system) {
     88	case SYS_DVBT:
     89	case SYS_DVBT2:
     90		cnr2qual   = vidtv_demod_t_cnr_2_qual;
     91		array_size = ARRAY_SIZE(vidtv_demod_t_cnr_2_qual);
     92		break;
     93
     94	case SYS_DVBS:
     95		cnr2qual   = vidtv_demod_s_cnr_2_qual;
     96		array_size = ARRAY_SIZE(vidtv_demod_s_cnr_2_qual);
     97		break;
     98
     99	case SYS_DVBS2:
    100		cnr2qual   = vidtv_demod_s2_cnr_2_qual;
    101		array_size = ARRAY_SIZE(vidtv_demod_s2_cnr_2_qual);
    102		break;
    103
    104	case SYS_DVBC_ANNEX_A:
    105		cnr2qual   = vidtv_demod_c_cnr_2_qual;
    106		array_size = ARRAY_SIZE(vidtv_demod_c_cnr_2_qual);
    107		break;
    108
    109	default:
    110		dev_warn_ratelimited(dev,
    111				     "%s: unsupported delivery system: %u\n",
    112				     __func__,
    113				     c->delivery_system);
    114		break;
    115	}
    116
    117	for (i = 0; i < array_size; i++)
    118		if (cnr2qual[i].modulation == c->modulation &&
    119		    cnr2qual[i].fec == c->fec_inner)
    120			return &cnr2qual[i];
    121
    122	return NULL; /* not found */
    123}
    124
    125static void vidtv_clean_stats(struct dvb_frontend *fe)
    126{
    127	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
    128
    129	/* Fill the length of each status counter */
    130
    131	/* Signal is always available */
    132	c->strength.len = 1;
    133	c->strength.stat[0].scale = FE_SCALE_DECIBEL;
    134	c->strength.stat[0].svalue = 0;
    135
    136	/* Usually available only after Viterbi lock */
    137	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
    138	c->cnr.stat[0].svalue = 0;
    139	c->cnr.len = 1;
    140
    141	/* Those depends on full lock */
    142	c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
    143	c->pre_bit_error.stat[0].uvalue = 0;
    144	c->pre_bit_error.len = 1;
    145	c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
    146	c->pre_bit_count.stat[0].uvalue = 0;
    147	c->pre_bit_count.len = 1;
    148	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
    149	c->post_bit_error.stat[0].uvalue = 0;
    150	c->post_bit_error.len = 1;
    151	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
    152	c->post_bit_count.stat[0].uvalue = 0;
    153	c->post_bit_count.len = 1;
    154	c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
    155	c->block_error.stat[0].uvalue = 0;
    156	c->block_error.len = 1;
    157	c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
    158	c->block_count.stat[0].uvalue = 0;
    159	c->block_count.len = 1;
    160}
    161
    162static void vidtv_demod_update_stats(struct dvb_frontend *fe)
    163{
    164	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
    165	struct vidtv_demod_state *state = fe->demodulator_priv;
    166	u32 scale;
    167
    168	if (state->status & FE_HAS_LOCK) {
    169		scale = FE_SCALE_COUNTER;
    170		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
    171	} else {
    172		scale = FE_SCALE_NOT_AVAILABLE;
    173		c->cnr.stat[0].scale = scale;
    174	}
    175
    176	c->pre_bit_error.stat[0].scale = scale;
    177	c->pre_bit_count.stat[0].scale = scale;
    178	c->post_bit_error.stat[0].scale = scale;
    179	c->post_bit_count.stat[0].scale = scale;
    180	c->block_error.stat[0].scale = scale;
    181	c->block_count.stat[0].scale = scale;
    182
    183	/*
    184	 * Add a 0.5% of randomness at the signal strength and CNR,
    185	 * and make them different, as we want to have something closer
    186	 * to a real case scenario.
    187	 *
    188	 * Also, usually, signal strength is a negative number in dBm.
    189	 */
    190	c->strength.stat[0].svalue = state->tuner_cnr;
    191	c->strength.stat[0].svalue -= prandom_u32_max(state->tuner_cnr / 50);
    192	c->strength.stat[0].svalue -= 68000; /* Adjust to a better range */
    193
    194	c->cnr.stat[0].svalue = state->tuner_cnr;
    195	c->cnr.stat[0].svalue -= prandom_u32_max(state->tuner_cnr / 50);
    196}
    197
    198static int vidtv_demod_read_status(struct dvb_frontend *fe,
    199				   enum fe_status *status)
    200{
    201	struct vidtv_demod_state *state = fe->demodulator_priv;
    202	const struct vidtv_demod_cnr_to_qual_s *cnr2qual = NULL;
    203	struct vidtv_demod_config *config = &state->config;
    204	u16 snr = 0;
    205
    206	/* Simulate random lost of signal due to a bad-tuned channel */
    207	cnr2qual = vidtv_match_cnr_s(&state->frontend);
    208
    209	if (cnr2qual && state->tuner_cnr < cnr2qual->cnr_good &&
    210	    state->frontend.ops.tuner_ops.get_rf_strength) {
    211		state->frontend.ops.tuner_ops.get_rf_strength(&state->frontend,
    212							      &snr);
    213
    214		if (snr < cnr2qual->cnr_ok) {
    215			/* eventually lose the TS lock */
    216			if (prandom_u32_max(100) < config->drop_tslock_prob_on_low_snr)
    217				state->status = 0;
    218		} else {
    219			/* recover if the signal improves */
    220			if (prandom_u32_max(100) <
    221			    config->recover_tslock_prob_on_good_snr)
    222				state->status = FE_HAS_SIGNAL  |
    223						FE_HAS_CARRIER |
    224						FE_HAS_VITERBI |
    225						FE_HAS_SYNC    |
    226						FE_HAS_LOCK;
    227		}
    228	}
    229
    230	vidtv_demod_update_stats(&state->frontend);
    231
    232	*status = state->status;
    233
    234	return 0;
    235}
    236
    237static int vidtv_demod_read_signal_strength(struct dvb_frontend *fe,
    238					    u16 *strength)
    239{
    240	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
    241
    242	*strength = c->strength.stat[0].uvalue;
    243
    244	return 0;
    245}
    246
    247/*
    248 * NOTE:
    249 * This is implemented here just to be used as an example for real
    250 * demod drivers.
    251 *
    252 * Should only be implemented if it actually reads something from the hardware.
    253 * Also, it should check for the locks, in order to avoid report wrong data
    254 * to userspace.
    255 */
    256static int vidtv_demod_get_frontend(struct dvb_frontend *fe,
    257				    struct dtv_frontend_properties *p)
    258{
    259	return 0;
    260}
    261
    262static int vidtv_demod_set_frontend(struct dvb_frontend *fe)
    263{
    264	struct vidtv_demod_state *state = fe->demodulator_priv;
    265	u32 tuner_status = 0;
    266	int ret;
    267
    268	if (!fe->ops.tuner_ops.set_params)
    269		return 0;
    270
    271	fe->ops.tuner_ops.set_params(fe);
    272
    273	/* store the CNR returned by the tuner */
    274	ret = fe->ops.tuner_ops.get_rf_strength(fe, &state->tuner_cnr);
    275	if (ret < 0)
    276		return ret;
    277
    278	fe->ops.tuner_ops.get_status(fe, &tuner_status);
    279	state->status = (state->tuner_cnr > 0) ?  FE_HAS_SIGNAL  |
    280						    FE_HAS_CARRIER |
    281						    FE_HAS_VITERBI |
    282						    FE_HAS_SYNC    |
    283						    FE_HAS_LOCK	 :
    284						    0;
    285
    286	vidtv_demod_update_stats(fe);
    287
    288	if (fe->ops.i2c_gate_ctrl)
    289		fe->ops.i2c_gate_ctrl(fe, 0);
    290
    291	return 0;
    292}
    293
    294/*
    295 * NOTE:
    296 * This is implemented here just to be used as an example for real
    297 * demod drivers.
    298 *
    299 * Should only be implemented if the demod has support for DVB-S or DVB-S2
    300 */
    301static int vidtv_demod_set_tone(struct dvb_frontend *fe,
    302				enum fe_sec_tone_mode tone)
    303{
    304	return 0;
    305}
    306
    307/*
    308 * NOTE:
    309 * This is implemented here just to be used as an example for real
    310 * demod drivers.
    311 *
    312 * Should only be implemented if the demod has support for DVB-S or DVB-S2
    313 */
    314static int vidtv_demod_set_voltage(struct dvb_frontend *fe,
    315				   enum fe_sec_voltage voltage)
    316{
    317	return 0;
    318}
    319
    320/*
    321 * NOTE:
    322 * This is implemented here just to be used as an example for real
    323 * demod drivers.
    324 *
    325 * Should only be implemented if the demod has support for DVB-S or DVB-S2
    326 */
    327static int vidtv_send_diseqc_msg(struct dvb_frontend *fe,
    328				 struct dvb_diseqc_master_cmd *cmd)
    329{
    330	return 0;
    331}
    332
    333/*
    334 * NOTE:
    335 * This is implemented here just to be used as an example for real
    336 * demod drivers.
    337 *
    338 * Should only be implemented if the demod has support for DVB-S or DVB-S2
    339 */
    340static int vidtv_diseqc_send_burst(struct dvb_frontend *fe,
    341				   enum fe_sec_mini_cmd burst)
    342{
    343	return 0;
    344}
    345
    346static void vidtv_demod_release(struct dvb_frontend *fe)
    347{
    348	struct vidtv_demod_state *state = fe->demodulator_priv;
    349
    350	kfree(state);
    351}
    352
    353static const struct dvb_frontend_ops vidtv_demod_ops = {
    354	.delsys = {
    355		SYS_DVBT,
    356		SYS_DVBT2,
    357		SYS_DVBC_ANNEX_A,
    358		SYS_DVBS,
    359		SYS_DVBS2,
    360	},
    361
    362	.info = {
    363		.name                   = "Dummy demod for DVB-T/T2/C/S/S2",
    364		.frequency_min_hz       = 51 * MHz,
    365		.frequency_max_hz       = 2150 * MHz,
    366		.frequency_stepsize_hz  = 62500,
    367		.frequency_tolerance_hz = 29500 * kHz,
    368		.symbol_rate_min        = 1000000,
    369		.symbol_rate_max        = 45000000,
    370
    371		.caps = FE_CAN_FEC_1_2 |
    372			FE_CAN_FEC_2_3 |
    373			FE_CAN_FEC_3_4 |
    374			FE_CAN_FEC_4_5 |
    375			FE_CAN_FEC_5_6 |
    376			FE_CAN_FEC_6_7 |
    377			FE_CAN_FEC_7_8 |
    378			FE_CAN_FEC_8_9 |
    379			FE_CAN_QAM_16 |
    380			FE_CAN_QAM_64 |
    381			FE_CAN_QAM_32 |
    382			FE_CAN_QAM_128 |
    383			FE_CAN_QAM_256 |
    384			FE_CAN_QAM_AUTO |
    385			FE_CAN_QPSK |
    386			FE_CAN_FEC_AUTO |
    387			FE_CAN_INVERSION_AUTO |
    388			FE_CAN_TRANSMISSION_MODE_AUTO |
    389			FE_CAN_GUARD_INTERVAL_AUTO |
    390			FE_CAN_HIERARCHY_AUTO,
    391	},
    392
    393	.release = vidtv_demod_release,
    394
    395	.set_frontend = vidtv_demod_set_frontend,
    396	.get_frontend = vidtv_demod_get_frontend,
    397
    398	.read_status          = vidtv_demod_read_status,
    399	.read_signal_strength = vidtv_demod_read_signal_strength,
    400
    401	/* For DVB-S/S2 */
    402	.set_voltage		= vidtv_demod_set_voltage,
    403	.set_tone		= vidtv_demod_set_tone,
    404	.diseqc_send_master_cmd	= vidtv_send_diseqc_msg,
    405	.diseqc_send_burst	= vidtv_diseqc_send_burst,
    406
    407};
    408
    409static const struct i2c_device_id vidtv_demod_i2c_id_table[] = {
    410	{"dvb_vidtv_demod", 0},
    411	{}
    412};
    413MODULE_DEVICE_TABLE(i2c, vidtv_demod_i2c_id_table);
    414
    415static int vidtv_demod_i2c_probe(struct i2c_client *client,
    416				 const struct i2c_device_id *id)
    417{
    418	struct vidtv_tuner_config *config = client->dev.platform_data;
    419	struct vidtv_demod_state *state;
    420
    421	/* allocate memory for the internal state */
    422	state = kzalloc(sizeof(*state), GFP_KERNEL);
    423	if (!state)
    424		return -ENOMEM;
    425
    426	/* create dvb_frontend */
    427	memcpy(&state->frontend.ops,
    428	       &vidtv_demod_ops,
    429	       sizeof(struct dvb_frontend_ops));
    430
    431	memcpy(&state->config, config, sizeof(state->config));
    432
    433	state->frontend.demodulator_priv = state;
    434	i2c_set_clientdata(client, state);
    435
    436	vidtv_clean_stats(&state->frontend);
    437
    438	return 0;
    439}
    440
    441static int vidtv_demod_i2c_remove(struct i2c_client *client)
    442{
    443	struct vidtv_demod_state *state = i2c_get_clientdata(client);
    444
    445	kfree(state);
    446
    447	return 0;
    448}
    449
    450static struct i2c_driver vidtv_demod_i2c_driver = {
    451	.driver = {
    452		.name                = "dvb_vidtv_demod",
    453		.suppress_bind_attrs = true,
    454	},
    455	.probe    = vidtv_demod_i2c_probe,
    456	.remove   = vidtv_demod_i2c_remove,
    457	.id_table = vidtv_demod_i2c_id_table,
    458};
    459
    460module_i2c_driver(vidtv_demod_i2c_driver);
    461
    462MODULE_DESCRIPTION("Virtual DVB Demodulator Driver");
    463MODULE_AUTHOR("Daniel W. S. Almeida");
    464MODULE_LICENSE("GPL");