[media] siano: Convert it to report DVBv5 stats
authorMauro Carvalho Chehab <mchehab@redhat.com>
Sat, 9 Mar 2013 22:26:28 +0000 (19:26 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Thu, 21 Mar 2013 10:47:31 +0000 (07:47 -0300)
While this frontend provides a nice set of statistics, the
way it is currently reported to userspace is poor. Worse than
that, instead of using quality indicators that range from 0 to 65535,
as expected by userspace, most indicators range from 0 to 100.
Improve it by using DVBv5 statistics API. The legacy indicators
are still reported using the very same old way, but they're now
using a proper range (0 to 65535 for quality indicadors; 0.1 dB
for SNR).

Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/common/siano/smsdvb.c

index 04544f591df53911398c475737f7f2fdaf91716e..a5f52721154cfb2e4d4f7a3c1bc928341c9dc3fb 100644 (file)
@@ -49,7 +49,10 @@ struct smsdvb_client_t {
        struct completion       tune_done;
        struct completion       stats_done;
 
-       struct SMSHOSTLIB_STATISTICS_DVB_EX_S sms_stat_dvb;
+       int last_per;
+
+       int legacy_ber, legacy_per;
+
        int event_fe_state;
        int event_unc_state;
 };
@@ -61,6 +64,82 @@ static int sms_dbg;
 module_param_named(debug, sms_dbg, int, 0644);
 MODULE_PARM_DESC(debug, "set debug level (info=1, adv=2 (or-able))");
 
+/*
+ * This struct is a mix of RECEPTION_STATISTICS_EX_S and SRVM_SIGNAL_STATUS_S.
+ * It was obtained by comparing the way it was filled by the original code
+ */
+struct RECEPTION_STATISTICS_PER_SLICES_S {
+       u32 result;
+       u32 snr;
+       s32 inBandPower;
+       u32 tsPackets;
+       u32 etsPackets;
+       u32 constellation;
+       u32 hpCode;
+       u32 tpsSrvIndLP;
+       u32 tpsSrvIndHP;
+       u32 cellId;
+       u32 reason;
+       u32 requestId;
+       u32 ModemState;         /* from SMSHOSTLIB_DVB_MODEM_STATE_ET */
+
+       u32 BER;                /* Post Viterbi BER [1E-5] */
+       s32 RSSI;               /* dBm */
+       s32 CarrierOffset;      /* Carrier Offset in bin/1024 */
+
+       u32 IsRfLocked;         /* 0 - not locked, 1 - locked */
+       u32 IsDemodLocked;      /* 0 - not locked, 1 - locked */
+
+       u32 BERBitCount;        /* Total number of SYNC bits. */
+       u32 BERErrorCount;      /* Number of erronous SYNC bits. */
+
+       s32 MRC_SNR;            /* dB */
+       s32 MRC_InBandPwr;      /* In band power in dBM */
+       s32 MRC_RSSI;           /* dBm */
+};
+
+u32 sms_to_bw_table[] = {
+       [BW_8_MHZ]              = 8000000,
+       [BW_7_MHZ]              = 7000000,
+       [BW_6_MHZ]              = 6000000,
+       [BW_5_MHZ]              = 5000000,
+       [BW_2_MHZ]              = 2000000,
+       [BW_1_5_MHZ]            = 1500000,
+       [BW_ISDBT_1SEG]         = 6000000,
+       [BW_ISDBT_3SEG]         = 6000000,
+       [BW_ISDBT_13SEG]        = 6000000,
+};
+
+u32 sms_to_guard_interval_table[] = {
+       [0] = GUARD_INTERVAL_1_32,
+       [1] = GUARD_INTERVAL_1_16,
+       [2] = GUARD_INTERVAL_1_8,
+       [3] = GUARD_INTERVAL_1_4,
+};
+
+u32 sms_to_code_rate_table[] = {
+       [0] = FEC_1_2,
+       [1] = FEC_2_3,
+       [2] = FEC_3_4,
+       [3] = FEC_5_6,
+       [4] = FEC_7_8,
+};
+
+
+u32 sms_to_hierarchy_table[] = {
+       [0] = HIERARCHY_NONE,
+       [1] = HIERARCHY_1,
+       [2] = HIERARCHY_2,
+       [3] = HIERARCHY_4,
+};
+
+u32 sms_to_modulation_table[] = {
+       [0] = QPSK,
+       [1] = QAM_16,
+       [2] = QAM_64,
+       [3] = DQPSK,
+};
+
 static void smsdvb_print_dvb_stats(struct SMSHOSTLIB_STATISTICS_ST *p)
 {
        if (!(sms_dbg & 2))
@@ -244,93 +323,350 @@ static void sms_board_dvb3_event(struct smsdvb_client_t *client,
        }
 }
 
-static void smsdvb_update_dvb_stats(struct RECEPTION_STATISTICS_EX_S *pReceptionData,
+static void smsdvb_stats_not_ready(struct dvb_frontend *fe)
+{
+       struct smsdvb_client_t *client =
+               container_of(fe, struct smsdvb_client_t, frontend);
+       struct smscore_device_t *coredev = client->coredev;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       int i, n_layers;
+
+       switch (smscore_get_device_mode(coredev)) {
+       case DEVICE_MODE_ISDBT:
+       case DEVICE_MODE_ISDBT_BDA:
+               n_layers = 4;
+       default:
+               n_layers = 1;
+       }
+
+       /* Fill the length of each status counter */
+
+       /* Only global stats */
+       c->strength.len = 1;
+       c->cnr.len = 1;
+
+       /* Per-layer stats */
+       c->post_bit_error.len = n_layers;
+       c->post_bit_count.len = n_layers;
+       c->block_error.len = n_layers;
+       c->block_count.len = n_layers;
+
+       /* Signal is always available */
+       c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+       c->strength.stat[0].uvalue = 0;
+
+       /* Put all of them at FE_SCALE_NOT_AVAILABLE */
+       for (i = 0; i < n_layers; i++) {
+               c->cnr.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+               c->post_bit_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+               c->post_bit_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+               c->block_error.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+               c->block_count.stat[i].scale = FE_SCALE_NOT_AVAILABLE;
+       }
+}
+
+static inline int sms_to_mode(u32 mode)
+{
+       switch (mode) {
+       case 2:
+               return TRANSMISSION_MODE_2K;
+       case 4:
+               return TRANSMISSION_MODE_4K;
+       case 8:
+               return TRANSMISSION_MODE_8K;
+       }
+       return TRANSMISSION_MODE_AUTO;
+}
+
+static inline int sms_to_status(u32 is_demod_locked, u32 is_rf_locked)
+{
+       if (is_demod_locked)
+               return FE_HAS_SIGNAL  | FE_HAS_CARRIER | FE_HAS_VITERBI |
+                      FE_HAS_SYNC    | FE_HAS_LOCK;
+
+       if (is_rf_locked)
+               return FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+       return 0;
+}
+
+
+#define convert_from_table(value, table, defval) ({                    \
+       u32 __ret;                                                      \
+       if (value < ARRAY_SIZE(table))                                  \
+               __ret = table[value];                                   \
+       else                                                            \
+               __ret = defval;                                         \
+       __ret;                                                          \
+})
+
+#define sms_to_bw(value)                                               \
+       convert_from_table(value, sms_to_bw_table, 0);
+
+#define sms_to_guard_interval(value)                                   \
+       convert_from_table(value, sms_to_guard_interval_table,          \
+                          GUARD_INTERVAL_AUTO);
+
+#define sms_to_code_rate(value)                                                \
+       convert_from_table(value, sms_to_code_rate_table,               \
+                          FEC_NONE);
+
+#define sms_to_hierarchy(value)                                                \
+       convert_from_table(value, sms_to_hierarchy_table,               \
+                          FEC_NONE);
+
+#define sms_to_modulation(value)                                       \
+       convert_from_table(value, sms_to_modulation_table,              \
+                          FEC_NONE);
+
+static void smsdvb_update_tx_params(struct smsdvb_client_t *client,
+                                   struct TRANSMISSION_STATISTICS_S *p)
+{
+       struct dvb_frontend *fe = &client->frontend;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       c->frequency = p->Frequency;
+       client->fe_status = sms_to_status(p->IsDemodLocked, 0);
+       c->bandwidth_hz = sms_to_bw(p->Bandwidth);
+       c->transmission_mode = sms_to_mode(p->TransmissionMode);
+       c->guard_interval = sms_to_guard_interval(p->GuardInterval);
+       c->code_rate_HP = sms_to_code_rate(p->CodeRate);
+       c->code_rate_LP = sms_to_code_rate(p->LPCodeRate);
+       c->hierarchy = sms_to_hierarchy(p->Hierarchy);
+       c->modulation = sms_to_modulation(p->Constellation);
+}
+
+static void smsdvb_update_per_slices(struct smsdvb_client_t *client,
+                                    struct RECEPTION_STATISTICS_PER_SLICES_S *p)
+{
+       struct dvb_frontend *fe = &client->frontend;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+       client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked);
+       c->modulation = sms_to_modulation(p->constellation);
+
+       /* TS PER */
+       client->last_per = c->block_error.stat[0].uvalue;
+       c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+       c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+       c->block_error.stat[0].uvalue += p->etsPackets;
+       c->block_count.stat[0].uvalue += p->etsPackets + p->tsPackets;
+
+       /* BER */
+       c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+       c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+       c->post_bit_error.stat[0].uvalue += p->BERErrorCount;
+       c->post_bit_count.stat[0].uvalue += p->BERBitCount;
+
+       /* Legacy PER/BER */
+       client->legacy_per = (p->etsPackets * 65535) /
+                            (p->tsPackets + p->etsPackets);
+
+       /* Signal Strength, in DBm */
+       c->strength.stat[0].uvalue = p->RSSI * 1000;
+
+       /* Carrier to Noise ratio, in DB */
+       c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+       c->cnr.stat[0].svalue = p->snr * 1000;
+}
+
+static void smsdvb_update_dvb_stats(struct smsdvb_client_t *client,
                                    struct SMSHOSTLIB_STATISTICS_ST *p)
 {
+       struct dvb_frontend *fe = &client->frontend;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
        smsdvb_print_dvb_stats(p);
 
+       client->fe_status = sms_to_status(p->IsDemodLocked, p->IsRfLocked);
+
+       /* Update DVB modulation parameters */
+       c->frequency = p->Frequency;
+       client->fe_status = sms_to_status(p->IsDemodLocked, 0);
+       c->bandwidth_hz = sms_to_bw(p->Bandwidth);
+       c->transmission_mode = sms_to_mode(p->TransmissionMode);
+       c->guard_interval = sms_to_guard_interval(p->GuardInterval);
+       c->code_rate_HP = sms_to_code_rate(p->CodeRate);
+       c->code_rate_LP = sms_to_code_rate(p->LPCodeRate);
+       c->hierarchy = sms_to_hierarchy(p->Hierarchy);
+       c->modulation = sms_to_modulation(p->Constellation);
+
        /* update reception data */
-       pReceptionData->IsRfLocked = p->IsRfLocked;
-       pReceptionData->IsDemodLocked = p->IsDemodLocked;
-       pReceptionData->IsExternalLNAOn = p->IsExternalLNAOn;
-       pReceptionData->ModemState = p->ModemState;
-       pReceptionData->SNR = p->SNR;
-       pReceptionData->BER = p->BER;
-       pReceptionData->BERErrorCount = p->BERErrorCount;
-       pReceptionData->BERBitCount = p->BERBitCount;
-       pReceptionData->RSSI = p->RSSI;
-       CORRECT_STAT_RSSI(*pReceptionData);
-       pReceptionData->InBandPwr = p->InBandPwr;
-       pReceptionData->CarrierOffset = p->CarrierOffset;
-       pReceptionData->ErrorTSPackets = p->ErrorTSPackets;
-       pReceptionData->TotalTSPackets = p->TotalTSPackets;
+       c->lna = p->IsExternalLNAOn ? 1 : 0;
+
+       /* Carrier to Noise ratio, in DB */
+       c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+       c->cnr.stat[0].svalue = p->SNR * 1000;
+
+       /* Signal Strength, in DBm */
+       c->strength.stat[0].uvalue = p->RSSI * 1000;
+
+       /* TS PER */
+       client->last_per = c->block_error.stat[0].uvalue;
+       c->block_error.stat[0].scale = FE_SCALE_COUNTER;
+       c->block_count.stat[0].scale = FE_SCALE_COUNTER;
+       c->block_error.stat[0].uvalue += p->ErrorTSPackets;
+       c->block_count.stat[0].uvalue += p->TotalTSPackets;
+
+       /* BER */
+       c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+       c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+       c->post_bit_error.stat[0].uvalue += p->BERErrorCount;
+       c->post_bit_count.stat[0].uvalue += p->BERBitCount;
+
+       /* Legacy PER/BER */
+       client->legacy_ber = p->BER;
 };
 
-static void smsdvb_update_isdbt_stats(struct RECEPTION_STATISTICS_EX_S *pReceptionData,
+static void smsdvb_update_isdbt_stats(struct smsdvb_client_t *client,
                                      struct SMSHOSTLIB_STATISTICS_ISDBT_ST *p)
 {
+       struct dvb_frontend *fe = &client->frontend;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr;
+       int i, n_layers;
+
        smsdvb_print_isdb_stats(p);
 
+       /* Update ISDB-T transmission parameters */
+       c->frequency = p->Frequency;
+       client->fe_status = sms_to_status(p->IsDemodLocked, 0);
+       c->bandwidth_hz = sms_to_bw(p->Bandwidth);
+       c->transmission_mode = sms_to_mode(p->TransmissionMode);
+       c->guard_interval = sms_to_guard_interval(p->GuardInterval);
+       c->isdbt_partial_reception = p->PartialReception ? 1 : 0;
+       n_layers = p->NumOfLayers;
+       if (n_layers < 1)
+               n_layers = 1;
+       if (n_layers > 3)
+               n_layers = 3;
+       c->isdbt_layer_enabled = 0;
+
        /* update reception data */
-       pReceptionData->IsRfLocked = p->IsRfLocked;
-       pReceptionData->IsDemodLocked = p->IsDemodLocked;
-       pReceptionData->IsExternalLNAOn = p->IsExternalLNAOn;
-       pReceptionData->ModemState = p->ModemState;
-       pReceptionData->SNR = p->SNR;
-       pReceptionData->BER = p->LayerInfo[0].BER;
-       pReceptionData->BERErrorCount = p->LayerInfo[0].BERErrorCount;
-       pReceptionData->BERBitCount = p->LayerInfo[0].BERBitCount;
-       pReceptionData->RSSI = p->RSSI;
-       CORRECT_STAT_RSSI(*pReceptionData);
-       pReceptionData->InBandPwr = p->InBandPwr;
-
-       pReceptionData->CarrierOffset = p->CarrierOffset;
-       pReceptionData->ErrorTSPackets = p->LayerInfo[0].ErrorTSPackets;
-       pReceptionData->TotalTSPackets = p->LayerInfo[0].TotalTSPackets;
-       pReceptionData->MFER = 0;
+       c->lna = p->IsExternalLNAOn ? 1 : 0;
 
-       /* TS PER */
-       if ((p->LayerInfo[0].TotalTSPackets +
-                p->LayerInfo[0].ErrorTSPackets) > 0) {
-               pReceptionData->TS_PER = (p->LayerInfo[0].ErrorTSPackets
-                               * 100) / (p->LayerInfo[0].TotalTSPackets
-                               + p->LayerInfo[0].ErrorTSPackets);
-       } else {
-               pReceptionData->TS_PER = 0;
+       /* Carrier to Noise ratio, in DB */
+       c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+       c->cnr.stat[0].svalue = p->SNR * 1000;
+
+       /* Signal Strength, in DBm */
+       c->strength.stat[0].uvalue = p->RSSI * 1000;
+
+       client->last_per = c->block_error.stat[0].uvalue;
+
+       /* Clears global counters, as the code below will sum it again */
+       c->block_error.stat[0].uvalue = 0;
+       c->block_count.stat[0].uvalue = 0;
+       c->post_bit_error.stat[0].uvalue = 0;
+       c->post_bit_count.stat[0].uvalue = 0;
+
+       for (i = 0; i < n_layers; i++) {
+               lr = &p->LayerInfo[i];
+
+               /* Update per-layer transmission parameters */
+               if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) {
+                       c->isdbt_layer_enabled |= 1 << i;
+                       c->layer[i].segment_count = lr->NumberOfSegments;
+               } else {
+                       continue;
+               }
+               c->layer[i].modulation = sms_to_modulation(lr->Constellation);
+
+               /* TS PER */
+               c->block_error.stat[i].scale = FE_SCALE_COUNTER;
+               c->block_count.stat[i].scale = FE_SCALE_COUNTER;
+               c->block_error.stat[i].uvalue += lr->ErrorTSPackets;
+               c->block_count.stat[i].uvalue += lr->TotalTSPackets;
+
+               /* Update global PER counter */
+               c->block_error.stat[0].uvalue += lr->ErrorTSPackets;
+               c->block_count.stat[0].uvalue += lr->TotalTSPackets;
+
+               /* BER */
+               c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER;
+               c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER;
+               c->post_bit_error.stat[i].uvalue += lr->BERErrorCount;
+               c->post_bit_count.stat[i].uvalue += lr->BERBitCount;
+
+               /* Update global BER counter */
+               c->post_bit_error.stat[0].uvalue += lr->BERErrorCount;
+               c->post_bit_count.stat[0].uvalue += lr->BERBitCount;
        }
 }
 
-static void smsdvb_update_isdbt_stats_ex(struct RECEPTION_STATISTICS_EX_S *pReceptionData,
-                                   struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p)
+static void smsdvb_update_isdbt_stats_ex(struct smsdvb_client_t *client,
+                                        struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST *p)
 {
+       struct dvb_frontend *fe = &client->frontend;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+       struct SMSHOSTLIB_ISDBT_LAYER_STAT_ST *lr;
+       int i, n_layers;
+
        smsdvb_print_isdb_stats_ex(p);
 
+       /* Update ISDB-T transmission parameters */
+       c->frequency = p->Frequency;
+       client->fe_status = sms_to_status(p->IsDemodLocked, 0);
+       c->bandwidth_hz = sms_to_bw(p->Bandwidth);
+       c->transmission_mode = sms_to_mode(p->TransmissionMode);
+       c->guard_interval = sms_to_guard_interval(p->GuardInterval);
+       c->isdbt_partial_reception = p->PartialReception ? 1 : 0;
+       n_layers = p->NumOfLayers;
+       if (n_layers < 1)
+               n_layers = 1;
+       if (n_layers > 3)
+               n_layers = 3;
+       c->isdbt_layer_enabled = 0;
+
        /* update reception data */
-       pReceptionData->IsRfLocked = p->IsRfLocked;
-       pReceptionData->IsDemodLocked = p->IsDemodLocked;
-       pReceptionData->IsExternalLNAOn = p->IsExternalLNAOn;
-       pReceptionData->ModemState = p->ModemState;
-       pReceptionData->SNR = p->SNR;
-       pReceptionData->BER = p->LayerInfo[0].BER;
-       pReceptionData->BERErrorCount = p->LayerInfo[0].BERErrorCount;
-       pReceptionData->BERBitCount = p->LayerInfo[0].BERBitCount;
-       pReceptionData->RSSI = p->RSSI;
-       CORRECT_STAT_RSSI(*pReceptionData);
-       pReceptionData->InBandPwr = p->InBandPwr;
-
-       pReceptionData->CarrierOffset = p->CarrierOffset;
-       pReceptionData->ErrorTSPackets = p->LayerInfo[0].ErrorTSPackets;
-       pReceptionData->TotalTSPackets = p->LayerInfo[0].TotalTSPackets;
-       pReceptionData->MFER = 0;
+       c->lna = p->IsExternalLNAOn ? 1 : 0;
 
-       /* TS PER */
-       if ((p->LayerInfo[0].TotalTSPackets +
-                p->LayerInfo[0].ErrorTSPackets) > 0) {
-               pReceptionData->TS_PER = (p->LayerInfo[0].ErrorTSPackets
-                               * 100) / (p->LayerInfo[0].TotalTSPackets
-                               + p->LayerInfo[0].ErrorTSPackets);
-       } else {
-               pReceptionData->TS_PER = 0;
+       /* Carrier to Noise ratio, in DB */
+       c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+       c->cnr.stat[0].svalue = p->SNR * 1000;
+
+       /* Signal Strength, in DBm */
+       c->strength.stat[0].uvalue = p->RSSI * 1000;
+
+       client->last_per = c->block_error.stat[0].uvalue;
+
+       /* Clears global counters, as the code below will sum it again */
+       c->block_error.stat[0].uvalue = 0;
+       c->block_count.stat[0].uvalue = 0;
+       c->post_bit_error.stat[0].uvalue = 0;
+       c->post_bit_count.stat[0].uvalue = 0;
+
+       for (i = 0; i < n_layers; i++) {
+               lr = &p->LayerInfo[i];
+
+               /* Update per-layer transmission parameters */
+               if (lr->NumberOfSegments > 0 && lr->NumberOfSegments < 13) {
+                       c->isdbt_layer_enabled |= 1 << i;
+                       c->layer[i].segment_count = lr->NumberOfSegments;
+               } else {
+                       continue;
+               }
+               c->layer[i].modulation = sms_to_modulation(lr->Constellation);
+
+               /* TS PER */
+               c->block_error.stat[i].scale = FE_SCALE_COUNTER;
+               c->block_count.stat[i].scale = FE_SCALE_COUNTER;
+               c->block_error.stat[i].uvalue += lr->ErrorTSPackets;
+               c->block_count.stat[i].uvalue += lr->TotalTSPackets;
+
+               /* Update global PER counter */
+               c->block_error.stat[0].uvalue += lr->ErrorTSPackets;
+               c->block_count.stat[0].uvalue += lr->TotalTSPackets;
+
+               /* BER */
+               c->post_bit_error.stat[i].scale = FE_SCALE_COUNTER;
+               c->post_bit_count.stat[i].scale = FE_SCALE_COUNTER;
+               c->post_bit_error.stat[i].uvalue += lr->BERErrorCount;
+               c->post_bit_count.stat[i].uvalue += lr->BERBitCount;
+
+               /* Update global BER counter */
+               c->post_bit_error.stat[0].uvalue += lr->BERErrorCount;
+               c->post_bit_count.stat[0].uvalue += lr->BERBitCount;
        }
 }
 
@@ -339,13 +675,14 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
        struct smsdvb_client_t *client = (struct smsdvb_client_t *) context;
        struct SmsMsgHdr_ST *phdr = (struct SmsMsgHdr_ST *) (((u8 *) cb->p)
                        + cb->offset);
-       u32 *pMsgData = (u32 *) phdr + 1;
-       /*u32 MsgDataLen = phdr->msgLength - sizeof(struct SmsMsgHdr_ST);*/
+       void *p = phdr + 1;
+       struct dvb_frontend *fe = &client->frontend;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        bool is_status_update = false;
 
        switch (phdr->msgType) {
        case MSG_SMS_DVBT_BDA_DATA:
-               dvb_dmx_swfilter(&client->demux, (u8 *)(phdr + 1),
+               dvb_dmx_swfilter(&client->demux, p,
                                 cb->size - sizeof(struct SmsMsgHdr_ST));
                break;
 
@@ -355,166 +692,64 @@ static int smsdvb_onresponse(void *context, struct smscore_buffer_t *cb)
                break;
 
        case MSG_SMS_SIGNAL_DETECTED_IND:
-               client->sms_stat_dvb.TransmissionData.IsDemodLocked = true;
+               client->fe_status = FE_HAS_SIGNAL  | FE_HAS_CARRIER |
+                                   FE_HAS_VITERBI | FE_HAS_SYNC    |
+                                   FE_HAS_LOCK;
+
                is_status_update = true;
                break;
 
        case MSG_SMS_NO_SIGNAL_IND:
-               client->sms_stat_dvb.TransmissionData.IsDemodLocked = false;
+               client->fe_status = 0;
+
                is_status_update = true;
                break;
 
-       case MSG_SMS_TRANSMISSION_IND: {
-
-               pMsgData++;
-               memcpy(&client->sms_stat_dvb.TransmissionData, pMsgData,
-                               sizeof(struct TRANSMISSION_STATISTICS_S));
+       case MSG_SMS_TRANSMISSION_IND:
+               smsdvb_update_tx_params(client, p);
 
-#if 1
-               /*
-                * FIXME: newer driver doesn't have those fixes
-                * Are those firmware-specific stuff?
-                */
-
-               /* Mo need to correct guard interval
-                * (as opposed to old statistics message).
-                */
-               CORRECT_STAT_BANDWIDTH(client->sms_stat_dvb.TransmissionData);
-               CORRECT_STAT_TRANSMISSON_MODE(
-                               client->sms_stat_dvb.TransmissionData);
-#endif
                is_status_update = true;
                break;
-       }
-       case MSG_SMS_HO_PER_SLICES_IND: {
-               struct RECEPTION_STATISTICS_EX_S *pReceptionData =
-                               &client->sms_stat_dvb.ReceptionData;
-               struct SRVM_SIGNAL_STATUS_S SignalStatusData;
-
-               pMsgData++;
-               SignalStatusData.result = pMsgData[0];
-               SignalStatusData.snr = pMsgData[1];
-               SignalStatusData.inBandPower = (s32) pMsgData[2];
-               SignalStatusData.tsPackets = pMsgData[3];
-               SignalStatusData.etsPackets = pMsgData[4];
-               SignalStatusData.constellation = pMsgData[5];
-               SignalStatusData.hpCode = pMsgData[6];
-               SignalStatusData.tpsSrvIndLP = pMsgData[7] & 0x03;
-               SignalStatusData.tpsSrvIndHP = pMsgData[8] & 0x03;
-               SignalStatusData.cellId = pMsgData[9] & 0xFFFF;
-               SignalStatusData.reason = pMsgData[10];
-               SignalStatusData.requestId = pMsgData[11];
-               pReceptionData->IsRfLocked = pMsgData[16];
-               pReceptionData->IsDemodLocked = pMsgData[17];
-               pReceptionData->ModemState = pMsgData[12];
-               pReceptionData->SNR = pMsgData[1];
-               pReceptionData->BER = pMsgData[13];
-               pReceptionData->RSSI = pMsgData[14];
-               CORRECT_STAT_RSSI(client->sms_stat_dvb.ReceptionData);
-
-               pReceptionData->InBandPwr = (s32) pMsgData[2];
-               pReceptionData->CarrierOffset = (s32) pMsgData[15];
-               pReceptionData->TotalTSPackets = pMsgData[3];
-               pReceptionData->ErrorTSPackets = pMsgData[4];
 
-               /* TS PER */
-               if ((SignalStatusData.tsPackets + SignalStatusData.etsPackets)
-                               > 0) {
-                       pReceptionData->TS_PER = (SignalStatusData.etsPackets
-                                       * 100) / (SignalStatusData.tsPackets
-                                       + SignalStatusData.etsPackets);
-               } else {
-                       pReceptionData->TS_PER = 0;
-               }
-
-               pReceptionData->BERBitCount = pMsgData[18];
-               pReceptionData->BERErrorCount = pMsgData[19];
-
-               pReceptionData->MRC_SNR = pMsgData[20];
-               pReceptionData->MRC_InBandPwr = pMsgData[21];
-               pReceptionData->MRC_RSSI = pMsgData[22];
+       case MSG_SMS_HO_PER_SLICES_IND:
+               smsdvb_update_per_slices(client, p);
 
                is_status_update = true;
                break;
-       }
-       case MSG_SMS_GET_STATISTICS_RES: {
-               union {
-                       struct SMSHOSTLIB_STATISTICS_ISDBT_ST  isdbt;
-                       struct SmsMsgStatisticsInfo_ST         dvb;
-               } *p = (void *) (phdr + 1);
-               struct RECEPTION_STATISTICS_EX_S *pReceptionData =
-                               &client->sms_stat_dvb.ReceptionData;
-
-               is_status_update = true;
 
+       case MSG_SMS_GET_STATISTICS_RES:
                switch (smscore_get_device_mode(client->coredev)) {
                case DEVICE_MODE_ISDBT:
                case DEVICE_MODE_ISDBT_BDA:
-                       smsdvb_update_isdbt_stats(pReceptionData, &p->isdbt);
+                       smsdvb_update_isdbt_stats(client, p);
                        break;
                default:
-                       smsdvb_update_dvb_stats(pReceptionData, &p->dvb.Stat);
-               }
-               if (!pReceptionData->IsDemodLocked) {
-                       pReceptionData->SNR = 0;
-                       pReceptionData->BER = 0;
-                       pReceptionData->BERErrorCount = 0;
-                       pReceptionData->InBandPwr = 0;
-                       pReceptionData->ErrorTSPackets = 0;
+                       smsdvb_update_dvb_stats(client, p);
                }
 
+               is_status_update = true;
                break;
-       }
-       case MSG_SMS_GET_STATISTICS_EX_RES: {
-               union {
-                       struct SMSHOSTLIB_STATISTICS_ISDBT_EX_ST isdbt;
-                       struct SMSHOSTLIB_STATISTICS_ST          dvb;
-               } *p = (void *) (phdr + 1);
-               struct RECEPTION_STATISTICS_EX_S *pReceptionData =
-                               &client->sms_stat_dvb.ReceptionData;
 
+       /* Only for ISDB-T */
+       case MSG_SMS_GET_STATISTICS_EX_RES:
+               smsdvb_update_isdbt_stats_ex(client, p);
                is_status_update = true;
-
-               switch (smscore_get_device_mode(client->coredev)) {
-               case DEVICE_MODE_ISDBT:
-               case DEVICE_MODE_ISDBT_BDA:
-                       smsdvb_update_isdbt_stats_ex(pReceptionData, &p->isdbt);
-                       break;
-               default:
-                       smsdvb_update_dvb_stats(pReceptionData, &p->dvb);
-               }
-               if (!pReceptionData->IsDemodLocked) {
-                       pReceptionData->SNR = 0;
-                       pReceptionData->BER = 0;
-                       pReceptionData->BERErrorCount = 0;
-                       pReceptionData->InBandPwr = 0;
-                       pReceptionData->ErrorTSPackets = 0;
-               }
-
                break;
-       }
        default:
                sms_info("message not handled");
        }
        smscore_putbuffer(client->coredev, cb);
 
        if (is_status_update) {
-               if (client->sms_stat_dvb.ReceptionData.IsDemodLocked) {
-                       client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER
-                               | FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+               if (client->fe_status == FE_HAS_LOCK) {
                        sms_board_dvb3_event(client, DVB3_EVENT_FE_LOCK);
-                       if (client->sms_stat_dvb.ReceptionData.ErrorTSPackets
-                                       == 0)
+                       if (client->last_per == c->block_error.stat[0].uvalue)
                                sms_board_dvb3_event(client, DVB3_EVENT_UNC_OK);
                        else
-                               sms_board_dvb3_event(client,
-                                               DVB3_EVENT_UNC_ERR);
-
+                               sms_board_dvb3_event(client, DVB3_EVENT_UNC_ERR);
                } else {
-                       if (client->sms_stat_dvb.ReceptionData.IsRfLocked)
-                               client->fe_status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
-                       else
-                               client->fe_status = 0;
+                       smsdvb_stats_not_ready(fe);
+
                        sms_board_dvb3_event(client, DVB3_EVENT_FE_UNLOCK);
                }
                complete(&client->stats_done);
@@ -612,13 +847,20 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
        Msg.msgFlags = 0;
        Msg.msgLength = sizeof(Msg);
 
-       /*
-        * Check for firmware version, to avoid breaking for old cards
-        */
-       if (client->coredev->fw_version >= 0x800)
-               Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ;
-       else
+       switch (smscore_get_device_mode(client->coredev)) {
+       case DEVICE_MODE_ISDBT:
+       case DEVICE_MODE_ISDBT_BDA:
+               /*
+               * Check for firmware version, to avoid breaking for old cards
+               */
+               if (client->coredev->fw_version >= 0x800)
+                       Msg.msgType = MSG_SMS_GET_STATISTICS_EX_REQ;
+               else
+                       Msg.msgType = MSG_SMS_GET_STATISTICS_REQ;
+               break;
+       default:
                Msg.msgType = MSG_SMS_GET_STATISTICS_REQ;
+       }
 
        rc = smsdvb_sendrequest_and_wait(client, &Msg, sizeof(Msg),
                                         &client->stats_done);
@@ -628,12 +870,12 @@ static int smsdvb_send_statistics_request(struct smsdvb_client_t *client)
 
 static inline int led_feedback(struct smsdvb_client_t *client)
 {
-       if (client->fe_status & FE_HAS_LOCK)
-               return sms_board_led_feedback(client->coredev,
-                       (client->sms_stat_dvb.ReceptionData.BER
-                       == 0) ? SMS_LED_HI : SMS_LED_LO);
-       else
+       if (!(client->fe_status & FE_HAS_LOCK))
                return sms_board_led_feedback(client->coredev, SMS_LED_OFF);
+
+       return sms_board_led_feedback(client->coredev,
+                                    (client->legacy_ber == 0) ?
+                                    SMS_LED_HI : SMS_LED_LO);
 }
 
 static int smsdvb_read_status(struct dvb_frontend *fe, fe_status_t *stat)
@@ -655,11 +897,12 @@ static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
        int rc;
        struct smsdvb_client_t *client;
+
        client = container_of(fe, struct smsdvb_client_t, frontend);
 
        rc = smsdvb_send_statistics_request(client);
 
-       *ber = client->sms_stat_dvb.ReceptionData.BER;
+       *ber = client->legacy_ber;
 
        led_feedback(client);
 
@@ -668,21 +911,21 @@ static int smsdvb_read_ber(struct dvb_frontend *fe, u32 *ber)
 
 static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int rc;
-
+       s32 power = (s32) c->strength.stat[0].uvalue;
        struct smsdvb_client_t *client;
+
        client = container_of(fe, struct smsdvb_client_t, frontend);
 
        rc = smsdvb_send_statistics_request(client);
 
-       if (client->sms_stat_dvb.ReceptionData.InBandPwr < -95)
+       if (power < -95)
                *strength = 0;
-               else if (client->sms_stat_dvb.ReceptionData.InBandPwr > -29)
-                       *strength = 100;
+               else if (power > -29)
+                       *strength = 65535;
                else
-                       *strength =
-                               (client->sms_stat_dvb.ReceptionData.InBandPwr
-                               + 95) * 3 / 2;
+                       *strength = (power + 95) * 65535 / 66;
 
        led_feedback(client);
 
@@ -691,13 +934,16 @@ static int smsdvb_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
 
 static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        int rc;
        struct smsdvb_client_t *client;
+
        client = container_of(fe, struct smsdvb_client_t, frontend);
 
        rc = smsdvb_send_statistics_request(client);
 
-       *snr = client->sms_stat_dvb.ReceptionData.SNR;
+       /* Preferred scale for SNR with legacy API: 0.1 dB */
+       *snr = c->cnr.stat[0].svalue / 100;
 
        led_feedback(client);
 
@@ -707,12 +953,14 @@ static int smsdvb_read_snr(struct dvb_frontend *fe, u16 *snr)
 static int smsdvb_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
        int rc;
+       struct dtv_frontend_properties *c = &fe->dtv_property_cache;
        struct smsdvb_client_t *client;
+
        client = container_of(fe, struct smsdvb_client_t, frontend);
 
        rc = smsdvb_send_statistics_request(client);
 
-       *ucblocks = client->sms_stat_dvb.ReceptionData.ErrorTSPackets;
+       *ucblocks = c->block_error.stat[0].uvalue;
 
        led_feedback(client);
 
@@ -743,7 +991,7 @@ static int smsdvb_dvbt_set_frontend(struct dvb_frontend *fe)
 
        int ret;
 
-       client->fe_status = FE_HAS_SIGNAL;
+       client->fe_status = 0;
        client->event_fe_state = -1;
        client->event_unc_state = -1;
        fe->dtv_property_cache.delivery_system = SYS_DVBT;
@@ -871,6 +1119,8 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe)
                container_of(fe, struct smsdvb_client_t, frontend);
        struct smscore_device_t *coredev = client->coredev;
 
+       smsdvb_stats_not_ready(fe);
+
        switch (smscore_get_device_mode(coredev)) {
        case DEVICE_MODE_DVBT:
        case DEVICE_MODE_DVBT_BDA:
@@ -883,150 +1133,10 @@ static int smsdvb_set_frontend(struct dvb_frontend *fe)
        }
 }
 
-static int smsdvb_get_frontend_dvb(struct dvb_frontend *fe)
-{
-       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       struct TRANSMISSION_STATISTICS_S *td =
-               &client->sms_stat_dvb.TransmissionData;
-
-       fep->frequency = td->Frequency;
-
-       switch (td->Bandwidth) {
-       case 6:
-               fep->bandwidth_hz = 6000000;
-               break;
-       case 7:
-               fep->bandwidth_hz = 7000000;
-               break;
-       case 8:
-               fep->bandwidth_hz = 8000000;
-               break;
-       }
-
-       switch (td->TransmissionMode) {
-       case 2:
-               fep->transmission_mode = TRANSMISSION_MODE_2K;
-               break;
-       case 8:
-               fep->transmission_mode = TRANSMISSION_MODE_8K;
-       }
-
-       switch (td->GuardInterval) {
-       case 0:
-               fep->guard_interval = GUARD_INTERVAL_1_32;
-               break;
-       case 1:
-               fep->guard_interval = GUARD_INTERVAL_1_16;
-               break;
-       case 2:
-               fep->guard_interval = GUARD_INTERVAL_1_8;
-               break;
-       case 3:
-               fep->guard_interval = GUARD_INTERVAL_1_4;
-               break;
-       }
-
-       switch (td->CodeRate) {
-       case 0:
-               fep->code_rate_HP = FEC_1_2;
-               break;
-       case 1:
-               fep->code_rate_HP = FEC_2_3;
-               break;
-       case 2:
-               fep->code_rate_HP = FEC_3_4;
-               break;
-       case 3:
-               fep->code_rate_HP = FEC_5_6;
-               break;
-       case 4:
-               fep->code_rate_HP = FEC_7_8;
-               break;
-       }
-
-       switch (td->LPCodeRate) {
-       case 0:
-               fep->code_rate_LP = FEC_1_2;
-               break;
-       case 1:
-               fep->code_rate_LP = FEC_2_3;
-               break;
-       case 2:
-               fep->code_rate_LP = FEC_3_4;
-               break;
-       case 3:
-               fep->code_rate_LP = FEC_5_6;
-               break;
-       case 4:
-               fep->code_rate_LP = FEC_7_8;
-               break;
-       }
-
-       switch (td->Constellation) {
-       case 0:
-               fep->modulation = QPSK;
-               break;
-       case 1:
-               fep->modulation = QAM_16;
-               break;
-       case 2:
-               fep->modulation = QAM_64;
-               break;
-       }
-
-       switch (td->Hierarchy) {
-       case 0:
-               fep->hierarchy = HIERARCHY_NONE;
-               break;
-       case 1:
-               fep->hierarchy = HIERARCHY_1;
-               break;
-       case 2:
-               fep->hierarchy = HIERARCHY_2;
-               break;
-       case 3:
-               fep->hierarchy = HIERARCHY_4;
-               break;
-       }
-
-       fep->inversion = INVERSION_AUTO;
-
-       return 0;
-}
-
-static int smsdvb_get_frontend_isdb(struct dvb_frontend *fe)
-{
-       struct dtv_frontend_properties *fep = &fe->dtv_property_cache;
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       struct TRANSMISSION_STATISTICS_S *td =
-               &client->sms_stat_dvb.TransmissionData;
-
-       fep->frequency = td->Frequency;
-       fep->bandwidth_hz = 6000000;
-       /* todo: retrive the other parameters */
-
-       return 0;
-}
-
+/* Nothing to do here, as stats are automatically updated */
 static int smsdvb_get_frontend(struct dvb_frontend *fe)
 {
-       struct smsdvb_client_t *client =
-               container_of(fe, struct smsdvb_client_t, frontend);
-       struct smscore_device_t *coredev = client->coredev;
-
-       switch (smscore_get_device_mode(coredev)) {
-       case DEVICE_MODE_DVBT:
-       case DEVICE_MODE_DVBT_BDA:
-               return smsdvb_get_frontend_dvb(fe);
-       case DEVICE_MODE_ISDBT:
-       case DEVICE_MODE_ISDBT_BDA:
-               return smsdvb_get_frontend_isdb(fe);
-       default:
-               return -EINVAL;
-       }
+       return 0;
 }
 
 static int smsdvb_init(struct dvb_frontend *fe)