[media] af9033: implement ber and ucb functions
authorHans-Frieder Vogt <hfvogt@gmx.net>
Sat, 7 Apr 2012 13:34:34 +0000 (10:34 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 14 May 2012 16:19:31 +0000 (13:19 -0300)
af9033: implement read_ber and read_ucblocks functions. Version 2 of patch that
reflects my findings on the behaviour of abort_cnt, err_cnt and bit_cnt:

- bit_cnt is always 0x2710 (10000)
- abort_cnt is between 0 and 0x2710
- err_cnt is between 0 and 640000 (= 0x2710 * 8 * 8)

in the current implementation BER is calculated as the number of bit errors per
processed bits, ignoring those bits that are already discarded and counted in
abort_cnt, i.e. UCBLOCKS.

Signed-off-by: Hans-Frieder Vogt <hfvogt@gmx.net>
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/frontends/af9033.c

index 2cb1f8d6955e3746d1a53d0154e83ffdde7cbc90..a38998286260043f9fdc9fa294c3bab8ccdd7306 100644 (file)
@@ -29,6 +29,10 @@ struct af9033_state {
        u32 bandwidth_hz;
        bool ts_mode_parallel;
        bool ts_mode_serial;
+
+       u32 ber;
+       u32 ucb;
+       unsigned long last_stat_check;
 };
 
 /* write multiple registers */
@@ -772,16 +776,73 @@ err:
        return ret;
 }
 
+static int af9033_update_ch_stat(struct af9033_state *state)
+{
+       int ret = 0;
+       u32 err_cnt, bit_cnt;
+       u16 abort_cnt;
+       u8 buf[7];
+
+       /* only update data every half second */
+       if (time_after(jiffies, state->last_stat_check + msecs_to_jiffies(500))) {
+               ret = af9033_rd_regs(state, 0x800032, buf, sizeof(buf));
+               if (ret < 0)
+                       goto err;
+               /* in 8 byte packets? */
+               abort_cnt = (buf[1] << 8) + buf[0];
+               /* in bits */
+               err_cnt = (buf[4] << 16) + (buf[3] << 8) + buf[2];
+               /* in 8 byte packets? always(?) 0x2710 = 10000 */
+               bit_cnt = (buf[6] << 8) + buf[5];
+
+               if (bit_cnt < abort_cnt) {
+                       abort_cnt = 1000;
+                       state->ber = 0xffffffff;
+               } else {
+                       /* 8 byte packets, that have not been rejected already */
+                       bit_cnt -= (u32)abort_cnt;
+                       if (bit_cnt == 0) {
+                               state->ber = 0xffffffff;
+                       } else {
+                               err_cnt -= (u32)abort_cnt * 8 * 8;
+                               bit_cnt *= 8 * 8;
+                               state->ber = err_cnt * (0xffffffff / bit_cnt);
+                       }
+               }
+               state->ucb += abort_cnt;
+               state->last_stat_check = jiffies;
+       }
+
+       return 0;
+err:
+       pr_debug("%s: failed=%d\n", __func__, ret);
+       return ret;
+}
+
 static int af9033_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-       *ber = 0;
+       struct af9033_state *state = fe->demodulator_priv;
+       int ret;
+
+       ret = af9033_update_ch_stat(state);
+       if (ret < 0)
+               return ret;
+
+       *ber = state->ber;
 
        return 0;
 }
 
 static int af9033_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
 {
-       *ucblocks = 0;
+       struct af9033_state *state = fe->demodulator_priv;
+       int ret;
+
+       ret = af9033_update_ch_stat(state);
+       if (ret < 0)
+               return ret;
+
+       *ucblocks = state->ucb;
 
        return 0;
 }