Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * The Virtual DVB test driver serves as a reference DVB driver and helps
0004  * validate the existing APIs in the media subsystem. It can also aid
0005  * developers working on userspace applications.
0006  *
0007  * Copyright (C) 2020 Daniel W. S. Almeida
0008  * Based on the example driver written by Emard <emard@softhome.net>
0009  */
0010 
0011 #include <linux/errno.h>
0012 #include <linux/i2c.h>
0013 #include <linux/init.h>
0014 #include <linux/kernel.h>
0015 #include <linux/module.h>
0016 #include <linux/printk.h>
0017 #include <linux/random.h>
0018 #include <linux/ratelimit.h>
0019 #include <linux/slab.h>
0020 #include <linux/string.h>
0021 #include <linux/workqueue.h>
0022 
0023 #include <media/dvb_frontend.h>
0024 
0025 #include "vidtv_demod.h"
0026 
0027 #define POLL_THRD_TIME 2000 /* ms */
0028 
0029 static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_c_cnr_2_qual[] = {
0030     /* from libdvbv5 source code, in milli db */
0031     { QAM_256, FEC_NONE,  34000, 38000},
0032     { QAM_64,  FEC_NONE,  30000, 34000},
0033 };
0034 
0035 static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_s_cnr_2_qual[] = {
0036     /* from libdvbv5 source code, in milli db */
0037     { QPSK, FEC_1_2,  7000, 10000},
0038     { QPSK, FEC_2_3,  9000, 12000},
0039     { QPSK, FEC_3_4, 10000, 13000},
0040     { QPSK, FEC_5_6, 11000, 14000},
0041     { QPSK, FEC_7_8, 12000, 15000},
0042 };
0043 
0044 static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_s2_cnr_2_qual[] = {
0045     /* from libdvbv5 source code, in milli db */
0046     { QPSK,  FEC_1_2,   9000,  12000},
0047     { QPSK,  FEC_2_3,  11000,  14000},
0048     { QPSK,  FEC_3_4,  12000,  15000},
0049     { QPSK,  FEC_5_6,  12000,  15000},
0050     { QPSK,  FEC_8_9,  13000,  16000},
0051     { QPSK,  FEC_9_10, 13500,  16500},
0052     { PSK_8, FEC_2_3,  14500,  17500},
0053     { PSK_8, FEC_3_4,  16000,  19000},
0054     { PSK_8, FEC_5_6,  17500,  20500},
0055     { PSK_8, FEC_8_9,  19000,  22000},
0056 };
0057 
0058 static const struct vidtv_demod_cnr_to_qual_s vidtv_demod_t_cnr_2_qual[] = {
0059     /* from libdvbv5 source code, in milli db*/
0060     {   QPSK, FEC_1_2,  4100,  5900},
0061     {   QPSK, FEC_2_3,  6100,  9600},
0062     {   QPSK, FEC_3_4,  7200, 12400},
0063     {   QPSK, FEC_5_6,  8500, 15600},
0064     {   QPSK, FEC_7_8,  9200, 17500},
0065     { QAM_16, FEC_1_2,  9800, 11800},
0066     { QAM_16, FEC_2_3, 12100, 15300},
0067     { QAM_16, FEC_3_4, 13400, 18100},
0068     { QAM_16, FEC_5_6, 14800, 21300},
0069     { QAM_16, FEC_7_8, 15700, 23600},
0070     { QAM_64, FEC_1_2, 14000, 16000},
0071     { QAM_64, FEC_2_3, 19900, 25400},
0072     { QAM_64, FEC_3_4, 24900, 27900},
0073     { QAM_64, FEC_5_6, 21300, 23300},
0074     { QAM_64, FEC_7_8, 22000, 24000},
0075 };
0076 
0077 static const struct vidtv_demod_cnr_to_qual_s *vidtv_match_cnr_s(struct dvb_frontend *fe)
0078 {
0079     const struct vidtv_demod_cnr_to_qual_s *cnr2qual = NULL;
0080     struct device *dev = fe->dvb->device;
0081     struct dtv_frontend_properties *c;
0082     u32 array_size = 0;
0083     u32 i;
0084 
0085     c = &fe->dtv_property_cache;
0086 
0087     switch (c->delivery_system) {
0088     case SYS_DVBT:
0089     case SYS_DVBT2:
0090         cnr2qual   = vidtv_demod_t_cnr_2_qual;
0091         array_size = ARRAY_SIZE(vidtv_demod_t_cnr_2_qual);
0092         break;
0093 
0094     case SYS_DVBS:
0095         cnr2qual   = vidtv_demod_s_cnr_2_qual;
0096         array_size = ARRAY_SIZE(vidtv_demod_s_cnr_2_qual);
0097         break;
0098 
0099     case SYS_DVBS2:
0100         cnr2qual   = vidtv_demod_s2_cnr_2_qual;
0101         array_size = ARRAY_SIZE(vidtv_demod_s2_cnr_2_qual);
0102         break;
0103 
0104     case SYS_DVBC_ANNEX_A:
0105         cnr2qual   = vidtv_demod_c_cnr_2_qual;
0106         array_size = ARRAY_SIZE(vidtv_demod_c_cnr_2_qual);
0107         break;
0108 
0109     default:
0110         dev_warn_ratelimited(dev,
0111                      "%s: unsupported delivery system: %u\n",
0112                      __func__,
0113                      c->delivery_system);
0114         break;
0115     }
0116 
0117     for (i = 0; i < array_size; i++)
0118         if (cnr2qual[i].modulation == c->modulation &&
0119             cnr2qual[i].fec == c->fec_inner)
0120             return &cnr2qual[i];
0121 
0122     return NULL; /* not found */
0123 }
0124 
0125 static void vidtv_clean_stats(struct dvb_frontend *fe)
0126 {
0127     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0128 
0129     /* Fill the length of each status counter */
0130 
0131     /* Signal is always available */
0132     c->strength.len = 1;
0133     c->strength.stat[0].scale = FE_SCALE_DECIBEL;
0134     c->strength.stat[0].svalue = 0;
0135 
0136     /* Usually available only after Viterbi lock */
0137     c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
0138     c->cnr.stat[0].svalue = 0;
0139     c->cnr.len = 1;
0140 
0141     /* Those depends on full lock */
0142     c->pre_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
0143     c->pre_bit_error.stat[0].uvalue = 0;
0144     c->pre_bit_error.len = 1;
0145     c->pre_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
0146     c->pre_bit_count.stat[0].uvalue = 0;
0147     c->pre_bit_count.len = 1;
0148     c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
0149     c->post_bit_error.stat[0].uvalue = 0;
0150     c->post_bit_error.len = 1;
0151     c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
0152     c->post_bit_count.stat[0].uvalue = 0;
0153     c->post_bit_count.len = 1;
0154     c->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
0155     c->block_error.stat[0].uvalue = 0;
0156     c->block_error.len = 1;
0157     c->block_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
0158     c->block_count.stat[0].uvalue = 0;
0159     c->block_count.len = 1;
0160 }
0161 
0162 static void vidtv_demod_update_stats(struct dvb_frontend *fe)
0163 {
0164     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0165     struct vidtv_demod_state *state = fe->demodulator_priv;
0166     u32 scale;
0167 
0168     if (state->status & FE_HAS_LOCK) {
0169         scale = FE_SCALE_COUNTER;
0170         c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
0171     } else {
0172         scale = FE_SCALE_NOT_AVAILABLE;
0173         c->cnr.stat[0].scale = scale;
0174     }
0175 
0176     c->pre_bit_error.stat[0].scale = scale;
0177     c->pre_bit_count.stat[0].scale = scale;
0178     c->post_bit_error.stat[0].scale = scale;
0179     c->post_bit_count.stat[0].scale = scale;
0180     c->block_error.stat[0].scale = scale;
0181     c->block_count.stat[0].scale = scale;
0182 
0183     /*
0184      * Add a 0.5% of randomness at the signal strength and CNR,
0185      * and make them different, as we want to have something closer
0186      * to a real case scenario.
0187      *
0188      * Also, usually, signal strength is a negative number in dBm.
0189      */
0190     c->strength.stat[0].svalue = state->tuner_cnr;
0191     c->strength.stat[0].svalue -= prandom_u32_max(state->tuner_cnr / 50);
0192     c->strength.stat[0].svalue -= 68000; /* Adjust to a better range */
0193 
0194     c->cnr.stat[0].svalue = state->tuner_cnr;
0195     c->cnr.stat[0].svalue -= prandom_u32_max(state->tuner_cnr / 50);
0196 }
0197 
0198 static int vidtv_demod_read_status(struct dvb_frontend *fe,
0199                    enum fe_status *status)
0200 {
0201     struct vidtv_demod_state *state = fe->demodulator_priv;
0202     const struct vidtv_demod_cnr_to_qual_s *cnr2qual = NULL;
0203     struct vidtv_demod_config *config = &state->config;
0204     u16 snr = 0;
0205 
0206     /* Simulate random lost of signal due to a bad-tuned channel */
0207     cnr2qual = vidtv_match_cnr_s(&state->frontend);
0208 
0209     if (cnr2qual && state->tuner_cnr < cnr2qual->cnr_good &&
0210         state->frontend.ops.tuner_ops.get_rf_strength) {
0211         state->frontend.ops.tuner_ops.get_rf_strength(&state->frontend,
0212                                   &snr);
0213 
0214         if (snr < cnr2qual->cnr_ok) {
0215             /* eventually lose the TS lock */
0216             if (prandom_u32_max(100) < config->drop_tslock_prob_on_low_snr)
0217                 state->status = 0;
0218         } else {
0219             /* recover if the signal improves */
0220             if (prandom_u32_max(100) <
0221                 config->recover_tslock_prob_on_good_snr)
0222                 state->status = FE_HAS_SIGNAL  |
0223                         FE_HAS_CARRIER |
0224                         FE_HAS_VITERBI |
0225                         FE_HAS_SYNC    |
0226                         FE_HAS_LOCK;
0227         }
0228     }
0229 
0230     vidtv_demod_update_stats(&state->frontend);
0231 
0232     *status = state->status;
0233 
0234     return 0;
0235 }
0236 
0237 static int vidtv_demod_read_signal_strength(struct dvb_frontend *fe,
0238                         u16 *strength)
0239 {
0240     struct dtv_frontend_properties *c = &fe->dtv_property_cache;
0241 
0242     *strength = c->strength.stat[0].uvalue;
0243 
0244     return 0;
0245 }
0246 
0247 /*
0248  * NOTE:
0249  * This is implemented here just to be used as an example for real
0250  * demod drivers.
0251  *
0252  * Should only be implemented if it actually reads something from the hardware.
0253  * Also, it should check for the locks, in order to avoid report wrong data
0254  * to userspace.
0255  */
0256 static int vidtv_demod_get_frontend(struct dvb_frontend *fe,
0257                     struct dtv_frontend_properties *p)
0258 {
0259     return 0;
0260 }
0261 
0262 static int vidtv_demod_set_frontend(struct dvb_frontend *fe)
0263 {
0264     struct vidtv_demod_state *state = fe->demodulator_priv;
0265     u32 tuner_status = 0;
0266     int ret;
0267 
0268     if (!fe->ops.tuner_ops.set_params)
0269         return 0;
0270 
0271     fe->ops.tuner_ops.set_params(fe);
0272 
0273     /* store the CNR returned by the tuner */
0274     ret = fe->ops.tuner_ops.get_rf_strength(fe, &state->tuner_cnr);
0275     if (ret < 0)
0276         return ret;
0277 
0278     fe->ops.tuner_ops.get_status(fe, &tuner_status);
0279     state->status = (state->tuner_cnr > 0) ?  FE_HAS_SIGNAL  |
0280                             FE_HAS_CARRIER |
0281                             FE_HAS_VITERBI |
0282                             FE_HAS_SYNC    |
0283                             FE_HAS_LOCK  :
0284                             0;
0285 
0286     vidtv_demod_update_stats(fe);
0287 
0288     if (fe->ops.i2c_gate_ctrl)
0289         fe->ops.i2c_gate_ctrl(fe, 0);
0290 
0291     return 0;
0292 }
0293 
0294 /*
0295  * NOTE:
0296  * This is implemented here just to be used as an example for real
0297  * demod drivers.
0298  *
0299  * Should only be implemented if the demod has support for DVB-S or DVB-S2
0300  */
0301 static int vidtv_demod_set_tone(struct dvb_frontend *fe,
0302                 enum fe_sec_tone_mode tone)
0303 {
0304     return 0;
0305 }
0306 
0307 /*
0308  * NOTE:
0309  * This is implemented here just to be used as an example for real
0310  * demod drivers.
0311  *
0312  * Should only be implemented if the demod has support for DVB-S or DVB-S2
0313  */
0314 static int vidtv_demod_set_voltage(struct dvb_frontend *fe,
0315                    enum fe_sec_voltage voltage)
0316 {
0317     return 0;
0318 }
0319 
0320 /*
0321  * NOTE:
0322  * This is implemented here just to be used as an example for real
0323  * demod drivers.
0324  *
0325  * Should only be implemented if the demod has support for DVB-S or DVB-S2
0326  */
0327 static int vidtv_send_diseqc_msg(struct dvb_frontend *fe,
0328                  struct dvb_diseqc_master_cmd *cmd)
0329 {
0330     return 0;
0331 }
0332 
0333 /*
0334  * NOTE:
0335  * This is implemented here just to be used as an example for real
0336  * demod drivers.
0337  *
0338  * Should only be implemented if the demod has support for DVB-S or DVB-S2
0339  */
0340 static int vidtv_diseqc_send_burst(struct dvb_frontend *fe,
0341                    enum fe_sec_mini_cmd burst)
0342 {
0343     return 0;
0344 }
0345 
0346 static void vidtv_demod_release(struct dvb_frontend *fe)
0347 {
0348     struct vidtv_demod_state *state = fe->demodulator_priv;
0349 
0350     kfree(state);
0351 }
0352 
0353 static const struct dvb_frontend_ops vidtv_demod_ops = {
0354     .delsys = {
0355         SYS_DVBT,
0356         SYS_DVBT2,
0357         SYS_DVBC_ANNEX_A,
0358         SYS_DVBS,
0359         SYS_DVBS2,
0360     },
0361 
0362     .info = {
0363         .name                   = "Dummy demod for DVB-T/T2/C/S/S2",
0364         .frequency_min_hz       = 51 * MHz,
0365         .frequency_max_hz       = 2150 * MHz,
0366         .frequency_stepsize_hz  = 62500,
0367         .frequency_tolerance_hz = 29500 * kHz,
0368         .symbol_rate_min        = 1000000,
0369         .symbol_rate_max        = 45000000,
0370 
0371         .caps = FE_CAN_FEC_1_2 |
0372             FE_CAN_FEC_2_3 |
0373             FE_CAN_FEC_3_4 |
0374             FE_CAN_FEC_4_5 |
0375             FE_CAN_FEC_5_6 |
0376             FE_CAN_FEC_6_7 |
0377             FE_CAN_FEC_7_8 |
0378             FE_CAN_FEC_8_9 |
0379             FE_CAN_QAM_16 |
0380             FE_CAN_QAM_64 |
0381             FE_CAN_QAM_32 |
0382             FE_CAN_QAM_128 |
0383             FE_CAN_QAM_256 |
0384             FE_CAN_QAM_AUTO |
0385             FE_CAN_QPSK |
0386             FE_CAN_FEC_AUTO |
0387             FE_CAN_INVERSION_AUTO |
0388             FE_CAN_TRANSMISSION_MODE_AUTO |
0389             FE_CAN_GUARD_INTERVAL_AUTO |
0390             FE_CAN_HIERARCHY_AUTO,
0391     },
0392 
0393     .release = vidtv_demod_release,
0394 
0395     .set_frontend = vidtv_demod_set_frontend,
0396     .get_frontend = vidtv_demod_get_frontend,
0397 
0398     .read_status          = vidtv_demod_read_status,
0399     .read_signal_strength = vidtv_demod_read_signal_strength,
0400 
0401     /* For DVB-S/S2 */
0402     .set_voltage        = vidtv_demod_set_voltage,
0403     .set_tone       = vidtv_demod_set_tone,
0404     .diseqc_send_master_cmd = vidtv_send_diseqc_msg,
0405     .diseqc_send_burst  = vidtv_diseqc_send_burst,
0406 
0407 };
0408 
0409 static const struct i2c_device_id vidtv_demod_i2c_id_table[] = {
0410     {"dvb_vidtv_demod", 0},
0411     {}
0412 };
0413 MODULE_DEVICE_TABLE(i2c, vidtv_demod_i2c_id_table);
0414 
0415 static int vidtv_demod_i2c_probe(struct i2c_client *client,
0416                  const struct i2c_device_id *id)
0417 {
0418     struct vidtv_tuner_config *config = client->dev.platform_data;
0419     struct vidtv_demod_state *state;
0420 
0421     /* allocate memory for the internal state */
0422     state = kzalloc(sizeof(*state), GFP_KERNEL);
0423     if (!state)
0424         return -ENOMEM;
0425 
0426     /* create dvb_frontend */
0427     memcpy(&state->frontend.ops,
0428            &vidtv_demod_ops,
0429            sizeof(struct dvb_frontend_ops));
0430 
0431     memcpy(&state->config, config, sizeof(state->config));
0432 
0433     state->frontend.demodulator_priv = state;
0434     i2c_set_clientdata(client, state);
0435 
0436     vidtv_clean_stats(&state->frontend);
0437 
0438     return 0;
0439 }
0440 
0441 static int vidtv_demod_i2c_remove(struct i2c_client *client)
0442 {
0443     struct vidtv_demod_state *state = i2c_get_clientdata(client);
0444 
0445     kfree(state);
0446 
0447     return 0;
0448 }
0449 
0450 static struct i2c_driver vidtv_demod_i2c_driver = {
0451     .driver = {
0452         .name                = "dvb_vidtv_demod",
0453         .suppress_bind_attrs = true,
0454     },
0455     .probe    = vidtv_demod_i2c_probe,
0456     .remove   = vidtv_demod_i2c_remove,
0457     .id_table = vidtv_demod_i2c_id_table,
0458 };
0459 
0460 module_i2c_driver(vidtv_demod_i2c_driver);
0461 
0462 MODULE_DESCRIPTION("Virtual DVB Demodulator Driver");
0463 MODULE_AUTHOR("Daniel W. S. Almeida");
0464 MODULE_LICENSE("GPL");