[media] cxd2841er: don't expose a dvbv5 stats to userspace if not available

The current code will expose a zero value if one of the stats is
not available, but this is not what userspace expects. Instead,
if something goes wrong on providing some stats, it should be
changing the scale to FE_SCALE_NOT_AVAILABLE.

So, change the logic to do the right thing.

Signed-off-by: Mauro Carvalho Chehab <mchehab@s-opensource.com>
diff --git a/drivers/media/dvb-frontends/cxd2841er.c b/drivers/media/dvb-frontends/cxd2841er.c
index 0c7d92a..721fb07 100644
--- a/drivers/media/dvb-frontends/cxd2841er.c
+++ b/drivers/media/dvb-frontends/cxd2841er.c
@@ -1330,7 +1330,7 @@
 	return 0;
 }
 
-static u32 cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv)
+static int cxd2841er_mon_read_ber_s(struct cxd2841er_priv *priv, u32 *ber)
 {
 	u8 data[11];
 	u32 bit_error, bit_count;
@@ -1365,25 +1365,25 @@
 			dev_dbg(&priv->i2c->dev,
 				"%s(): invalid bit_error %d, bit_count %d\n",
 				__func__, bit_error, bit_count);
-			return 0;
+			return -EINVAL;
 		}
 		temp_q = div_u64_rem(10000000ULL * bit_error,
 						bit_count, &temp_r);
 		if (bit_count != 1 && temp_r >= bit_count / 2)
 			temp_q++;
-		return temp_q;
+		*ber = temp_q;
+		return 0;
 	}
 	dev_dbg(&priv->i2c->dev, "%s(): no data available\n", __func__);
-	return 0;
+	return -EINVAL;
 }
 
 
-static u32 cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv)
+static int cxd2841er_mon_read_ber_s2(struct cxd2841er_priv *priv, u32 *ber)
 {
 	u8 data[5];
 	u32 bit_error, period;
 	u32 temp_q, temp_r;
-	u32 result = 0;
 
 	/* Set SLV-T Bank : 0xB2 */
 	cxd2841er_write_reg(priv, I2C_SLVT, 0x00, 0xb2);
@@ -1411,13 +1411,13 @@
 		if (period == 0) {
 			dev_dbg(&priv->i2c->dev,
 				"%s(): period is 0\n", __func__);
-			return 0;
+			return -EINVAL;
 		}
 		if (bit_error > (period * 64800)) {
 			dev_dbg(&priv->i2c->dev,
 				"%s(): invalid bit_err 0x%x period 0x%x\n",
 				__func__, bit_error, period);
-			return 0;
+			return -EINVAL;
 		}
 		/*
 		 * BER = bitError / (period * 64800)
@@ -1430,12 +1430,13 @@
 					period * 81, &temp_r);
 		if (temp_r >= period * 40)
 			temp_q++;
-		result = temp_q;
+		*ber = temp_q;
+		return 0;
 	} else {
 		dev_dbg(&priv->i2c->dev,
 			"%s(): no data available\n", __func__);
 	}
-	return result;
+	return -EINVAL;
 }
 
 static int cxd2841er_read_ber_t2(struct cxd2841er_priv *priv, u32 *ber)
@@ -1717,29 +1718,37 @@
 	return ((((u16)data[0] & 0x1F) << 8) | (u16)(data[1] & 0xFF)) << 3;
 }
 
-static int cxd2841er_read_ber(struct dvb_frontend *fe, u32 *ber)
+static void cxd2841er_read_ber(struct dvb_frontend *fe)
 {
 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 	struct cxd2841er_priv *priv = fe->demodulator_priv;
+	u32 ber = 0, ret;
 
 	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
-	*ber = 0;
 	switch (p->delivery_system) {
 	case SYS_DVBS:
-		*ber = cxd2841er_mon_read_ber_s(priv);
+		ret = cxd2841er_mon_read_ber_s(priv, &ber);
 		break;
 	case SYS_DVBS2:
-		*ber = cxd2841er_mon_read_ber_s2(priv);
+		ret = cxd2841er_mon_read_ber_s2(priv, &ber);
 		break;
 	case SYS_DVBT:
-		return cxd2841er_read_ber_t(priv, ber);
-	case SYS_DVBT2:
-		return cxd2841er_read_ber_t2(priv, ber);
-	default:
-		*ber = 0;
+		ret = cxd2841er_read_ber_t(priv, &ber);
 		break;
+	case SYS_DVBT2:
+		ret = cxd2841er_read_ber_t2(priv, &ber);
+		break;
+	default:
+		p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		return;
 	}
-	return 0;
+
+	if (!ret) {
+		p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+		p->post_bit_error.stat[0].uvalue = ber;
+	} else {
+		p->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	}
 }
 
 static void cxd2841er_read_signal_strength(struct dvb_frontend *fe)
@@ -1779,13 +1788,12 @@
 		p->strength.stat[0].uvalue = strength;
 		break;
 	default:
-		p->strength.stat[0].scale = FE_SCALE_RELATIVE;
-		p->strength.stat[0].uvalue = 0;
+		p->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 		break;
 	}
 }
 
-static int cxd2841er_read_snr(struct dvb_frontend *fe, u16 *snr)
+static void cxd2841er_read_snr(struct dvb_frontend *fe)
 {
 	u32 tmp = 0;
 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@@ -1809,34 +1817,39 @@
 	default:
 		dev_dbg(&priv->i2c->dev, "%s(): unknown delivery system %d\n",
 			__func__, p->delivery_system);
-		break;
+		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		return;
 	}
-	*snr = tmp & 0xffff;
-	return 0;
+
+	p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+	p->cnr.stat[0].svalue = tmp;
 }
 
-static int cxd2841er_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+static void cxd2841er_read_ucblocks(struct dvb_frontend *fe)
 {
 	struct dtv_frontend_properties *p = &fe->dtv_property_cache;
 	struct cxd2841er_priv *priv = fe->demodulator_priv;
+	u32 ucblocks;
 
 	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
 	switch (p->delivery_system) {
 	case SYS_DVBT:
-		cxd2841er_read_packet_errors_t(priv, ucblocks);
+		cxd2841er_read_packet_errors_t(priv, &ucblocks);
 		break;
 	case SYS_DVBT2:
-		cxd2841er_read_packet_errors_t2(priv, ucblocks);
+		cxd2841er_read_packet_errors_t2(priv, &ucblocks);
 		break;
 	case SYS_ISDBT:
-		cxd2841er_read_packet_errors_i(priv, ucblocks);
+		cxd2841er_read_packet_errors_i(priv, &ucblocks);
 		break;
 	default:
-		*ucblocks = 0;
-		break;
+		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+		return;
 	}
 	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
-	return 0;
+
+	p->block_error.stat[0].scale = FE_SCALE_COUNTER;
+	p->block_error.stat[0].uvalue = ucblocks;
 }
 
 static int cxd2841er_dvbt2_set_profile(
@@ -2956,8 +2969,6 @@
 				  struct dtv_frontend_properties *p)
 {
 	enum fe_status status = 0;
-	u16 snr = 0;
-	u32 errors = 0, ber = 0;
 	struct cxd2841er_priv *priv = fe->demodulator_priv;
 
 	dev_dbg(&priv->i2c->dev, "%s()\n", __func__);
@@ -2969,17 +2980,10 @@
 	cxd2841er_read_signal_strength(fe);
 
 	if (status & FE_HAS_LOCK) {
-		cxd2841er_read_snr(fe, &snr);
-		p->cnr.stat[0].scale = FE_SCALE_DECIBEL;
-		p->cnr.stat[0].svalue = snr;
+		cxd2841er_read_snr(fe);
+		cxd2841er_read_ucblocks(fe);
 
-		cxd2841er_read_ucblocks(fe, &errors);
-		p->block_error.stat[0].scale = FE_SCALE_COUNTER;
-		p->block_error.stat[0].uvalue = errors;
-
-		cxd2841er_read_ber(fe, &ber);
-		p->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
-		p->post_bit_error.stat[0].uvalue = ber;
+		cxd2841er_read_ber(fe);
 	} else {
 		p->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
 		p->block_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;