Michael Krufky wrote:
> On Fri, Dec 4, 2009 at 3:02 PM, VDR User <user....@gmail.com> wrote:
>> No activity in this thread for 2 weeks now.  Has there been any progress?

> I have stated that I like Manu's proposal, but I would prefer that the
> get_property (s2api) interface were used, because it totally provides
> an interface that is sufficient for this feature.

I've ported Manu's proposal to S2API way of handling it. It is just compiled
only. I haven't test it yet on a real driver.

Comments?

---

Add support for frontend statistics via S2API

The current DVB V3 API to handle statistics has two issues:
        - Retrieving several values can't be done atomically;
        - There's no indication about scale information.

This patch solves those two issues by adding a group of S2API
that handles the needed statistics operations. It basically ports the
proposal of Manu Abraham <abraham.m...@gmail.com> To S2API.

As the original patch, both of the above issues were addressed.

In order to demonstrate the changes on an existing driver for the new API, I've
implemented it at the cx24123 driver.

There are some advantages of using this approach over using the static structs
of the original proposal:
        - userspace can select an arbitrary number of parameters on his get 
request;
        - the latency to retrieve just one parameter is lower than retrieving
several parameters. On the cx24123 example, if user wants just signal strength,
the latency is the same as reading one register via i2c bus. If using the 
original
proposal, the latency would be 6 times worse, since you would need to get 3 
properties
at the same time;
        - the latency for reading all 3 parameters at the same time is equal to
the latency of the original proposal;
        - if newer statistics parameters will be needed in the future, it is 
just
a matter of adding additional S2API command/value pairs;
        - the DVB V3 calls can be easily implemented as a call to the new 
get_stats ops,
without adding extra latency time.

Thanks to Manu Abraham <abraham.m...@gmail.com> for his initial proposal.

Signed-off-by: Mauro Carvalho Chehab <mche...@redhat.com>


diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c 
b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -975,6 +975,16 @@ static struct dtv_cmds_h dtv_cmds[] = {
        _DTV_CMD(DTV_GUARD_INTERVAL, 0, 0),
        _DTV_CMD(DTV_TRANSMISSION_MODE, 0, 0),
        _DTV_CMD(DTV_HIERARCHY, 0, 0),
+
+       /* Statistics API */
+       _DTV_CMD(DTV_FE_QUALITY, 0, 0),
+       _DTV_CMD(DTV_FE_QUALITY_UNIT, 0, 0),
+       _DTV_CMD(DTV_FE_STRENGTH, 0, 0),
+       _DTV_CMD(DTV_FE_STRENGTH_UNIT, 0, 0),
+       _DTV_CMD(DTV_FE_ERROR, 0, 0),
+       _DTV_CMD(DTV_FE_ERROR_UNIT, 0, 0),
+       _DTV_CMD(DTV_FE_SIGNAL, 0, 0),
+       _DTV_CMD(DTV_FE_SIGNAL_UNIT, 0, 0),
 };
 
 static void dtv_property_dump(struct dtv_property *tvp)
@@ -1203,16 +1213,59 @@ static int dvb_frontend_ioctl_legacy(str
 static int dvb_frontend_ioctl_properties(struct inode *inode, struct file 
*file,
                        unsigned int cmd, void *parg);
 
+static int dtv_property_prepare_get_stats(struct dvb_frontend *fe,
+                                   struct dtv_property *tvp,
+                                   struct inode *inode, struct file *file)
+{
+       switch (tvp->cmd) {
+       case DTV_FE_QUALITY:
+               fe->dtv_property_cache.need_stats |= FE_NEED_QUALITY;
+               break;
+       case DTV_FE_QUALITY_UNIT:
+               fe->dtv_property_cache.need_stats |= FE_NEED_QUALITY_UNIT;
+               break;
+       case DTV_FE_STRENGTH:
+               fe->dtv_property_cache.need_stats |= FE_NEED_STRENGTH;
+               break;
+       case DTV_FE_STRENGTH_UNIT:
+               fe->dtv_property_cache.need_stats |= FE_NEED_STRENGTH_UNIT;
+               break;
+       case DTV_FE_ERROR:
+               fe->dtv_property_cache.need_stats |= FE_NEED_ERROR;
+               break;
+       case DTV_FE_ERROR_UNIT:
+               fe->dtv_property_cache.need_stats |= FE_NEED_ERROR_UNIT;
+               break;
+       case DTV_FE_SIGNAL:
+               fe->dtv_property_cache.need_stats |= FE_NEED_SIGNAL;
+               break;
+       case DTV_FE_SIGNAL_UNIT:
+               fe->dtv_property_cache.need_stats |= FE_NEED_SIGNAL_UNIT;
+               break;
+       case DTV_FE_UNC:
+               fe->dtv_property_cache.need_stats |= FE_NEED_SIGNAL;
+               break;
+       case DTV_FE_UNC_UNIT:
+               fe->dtv_property_cache.need_stats |= FE_NEED_SIGNAL_UNIT;
+               break;
+       default:
+               return 1;
+       };
+
+       return 0;
+}
+
 static int dtv_property_process_get(struct dvb_frontend *fe,
                                    struct dtv_property *tvp,
-                                   struct inode *inode, struct file *file)
+                                   struct inode *inode, struct file *file,
+                                   int need_get_ops)
 {
        int r = 0;
 
        dtv_property_dump(tvp);
 
        /* Allow the frontend to validate incoming properties */
-       if (fe->ops.get_property)
+       if (fe->ops.get_property && need_get_ops)
                r = fe->ops.get_property(fe, tvp);
 
        if (r < 0)
@@ -1329,6 +1382,38 @@ static int dtv_property_process_get(stru
        case DTV_ISDBS_TS_ID:
                tvp->u.data = fe->dtv_property_cache.isdbs_ts_id;
                break;
+
+       /* Quality measures */
+       case DTV_FE_QUALITY:
+               tvp->u.data = fe->dtv_property_cache.quality;
+               break;
+       case DTV_FE_QUALITY_UNIT:
+               tvp->u.data = fe->dtv_property_cache.quality_unit;
+               break;
+       case DTV_FE_STRENGTH:
+               tvp->u.data = fe->dtv_property_cache.strength;
+               break;
+       case DTV_FE_STRENGTH_UNIT:
+               tvp->u.data = fe->dtv_property_cache.strength_unit;
+               break;
+       case DTV_FE_ERROR:
+               tvp->u.data = fe->dtv_property_cache.error;
+               break;
+       case DTV_FE_ERROR_UNIT:
+               tvp->u.data = fe->dtv_property_cache.error_unit;
+               break;
+       case DTV_FE_SIGNAL:
+               tvp->u.data = fe->dtv_property_cache.signal;
+               break;
+       case DTV_FE_SIGNAL_UNIT:
+               tvp->u.data = fe->dtv_property_cache.signal_unit;
+               break;
+       case DTV_FE_UNC:
+               tvp->u.data = fe->dtv_property_cache.signal;
+               break;
+       case DTV_FE_UNC_UNIT:
+               tvp->u.data = fe->dtv_property_cache.signal_unit;
+               break;
        default:
                r = -1;
        }
@@ -1527,7 +1612,7 @@ static int dvb_frontend_ioctl_properties
 {
        struct dvb_device *dvbdev = file->private_data;
        struct dvb_frontend *fe = dvbdev->priv;
-       int err = 0;
+       int err = 0, need_get_ops;
 
        struct dtv_properties *tvps = NULL;
        struct dtv_property *tvp = NULL;
@@ -1591,8 +1676,29 @@ static int dvb_frontend_ioctl_properties
                        goto out;
                }
 
+               /*
+               * Do all get operations at once, instead of handling them
+               * individually
+               */
+               need_get_ops = 0;
+               fe->dtv_property_cache.need_stats = 0;
+               for (i = 0; i < tvps->num; i++)
+                       need_get_ops += dtv_property_prepare_get_stats(fe,
+                                                        tvp + i, inode, file);
+
+               if (!fe->dtv_property_cache.need_stats) {
+                       need_get_ops++;
+               } else {
+                       if (fe->ops.get_stats) {
+                               err = fe->ops.get_stats(fe);
+                               if (err < 0)
+                                       return err;
+                       }
+               }
+
                for (i = 0; i < tvps->num; i++) {
-                       (tvp + i)->result = dtv_property_process_get(fe, tvp + 
i, inode, file);
+                       (tvp + i)->result = dtv_property_process_get(fe,
+                                       tvp + i, inode, file, need_get_ops);
                        err |= (tvp + i)->result;
                }
 
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h 
b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -304,6 +304,7 @@ struct dvb_frontend_ops {
 
        int (*set_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
        int (*get_property)(struct dvb_frontend* fe, struct dtv_property* tvp);
+       int (*get_stats)(struct dvb_frontend* fe);
 };
 
 #define MAX_EVENT 8
@@ -358,6 +359,32 @@ struct dtv_frontend_properties {
 
        /* ISDB-T specifics */
        u32                     isdbs_ts_id;
+
+       /* Statistics group */
+
+#define FE_NEED_QUALITY                (1 << 0)
+#define FE_NEED_QUALITY_UNIT   (1 << 1)
+#define FE_NEED_STRENGTH       (1 << 2)
+#define FE_NEED_STRENGTH_UNIT  (1 << 3)
+#define FE_NEED_ERROR          (1 << 4)
+#define FE_NEED_ERROR_UNIT     (1 << 5)
+#define FE_NEED_UNC            (1 << 6)
+#define FE_NEED_UNC_UNIT       (1 << 7)
+#define FE_NEED_SIGNAL         (1 << 6)
+#define FE_NEED_SIGNAL_UNIT    (1 << 7)
+       int                     need_stats;
+
+       u32                     quality;
+       u32                     strength;
+       u32                     error;
+       u32                     unc;
+       u32                     signal;
+
+       enum fecap_quality_params       quality_unit;
+       enum fecap_scale_params         strength_unit;
+       enum fecap_error_params         error_unit;
+       enum fecap_unc_params           unc_unit;
+       enum fecap_scale_params         signal_unit;
 };
 
 struct dvb_frontend {
diff --git a/linux/drivers/media/dvb/frontends/cx24123.c 
b/linux/drivers/media/dvb/frontends/cx24123.c
--- a/linux/drivers/media/dvb/frontends/cx24123.c
+++ b/linux/drivers/media/dvb/frontends/cx24123.c
@@ -890,6 +890,66 @@ static int cx24123_read_status(struct dv
        return 0;
 }
 
+static int cx24123_get_stats(struct dvb_frontend* fe)
+{
+       struct cx24123_state *state = fe->demodulator_priv;
+       struct dtv_frontend_properties *prop = &fe->dtv_property_cache;
+
+       if (fe->dtv_property_cache.need_stats & FE_NEED_STRENGTH) {
+               /* larger = better */
+               prop->strength = cx24123_readreg(state, 0x3b) << 8;
+                       dprintk("Signal strength = %d\n", prop->strength);
+               fe->dtv_property_cache.need_stats &= ~FE_NEED_STRENGTH;
+       }
+
+       if (fe->dtv_property_cache.need_stats & FE_NEED_STRENGTH_UNIT) {
+               /* larger = better */
+               prop->strength_unit = FE_SCALE_UNKNOWN;
+               fe->dtv_property_cache.need_stats &= ~FE_NEED_STRENGTH_UNIT;
+       }
+
+       if (fe->dtv_property_cache.need_stats & FE_NEED_ERROR) {
+               /* The true bit error rate is this value divided by
+               the window size (set as 256 * 255) */
+               prop->error = ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
+                              (cx24123_readreg(state, 0x1d) << 8 |
+                              cx24123_readreg(state, 0x1e));
+
+               dprintk("BER = %d\n", prop->error);
+
+               fe->dtv_property_cache.need_stats &= ~FE_NEED_ERROR;
+       }
+
+       if (fe->dtv_property_cache.need_stats & FE_NEED_ERROR_UNIT) {
+               /* larger = better */
+               prop->strength_unit = FE_ERROR_BER;
+               fe->dtv_property_cache.need_stats &= ~FE_NEED_ERROR_UNIT;
+       }
+
+       if (fe->dtv_property_cache.need_stats & FE_NEED_QUALITY) {
+               /* Inverted raw Es/N0 count, totally bogus but better than the
+                  BER threshold. */
+               prop->quality = 65535 - (((u16)cx24123_readreg(state, 0x18) << 
8) |
+                                         (u16)cx24123_readreg(state, 0x19));
+
+               dprintk("read S/N index = %d\n", prop->quality);
+
+               fe->dtv_property_cache.need_stats &= ~FE_NEED_QUALITY;
+       }
+
+       if (fe->dtv_property_cache.need_stats & FE_NEED_QUALITY_UNIT) {
+               /* larger = better */
+               prop->strength_unit = FE_QUALITY_EsNo;
+               fe->dtv_property_cache.need_stats &= ~FE_NEED_QUALITY_UNIT;
+       }
+
+       /* Check if userspace requested a parameter that we can't handle*/
+       if (fe->dtv_property_cache.need_stats)
+               return -EINVAL;
+
+       return 0;
+}
+
 /*
  * Configured to return the measurement of errors in blocks,
  * because no UCBLOCKS value is available, so this value doubles up
@@ -897,43 +957,30 @@ static int cx24123_read_status(struct dv
  */
 static int cx24123_read_ber(struct dvb_frontend *fe, u32 *ber)
 {
-       struct cx24123_state *state = fe->demodulator_priv;
+       fe->dtv_property_cache.need_stats = FE_NEED_ERROR;
+       cx24123_get_stats(fe);
 
-       /* The true bit error rate is this value divided by
-          the window size (set as 256 * 255) */
-       *ber = ((cx24123_readreg(state, 0x1c) & 0x3f) << 16) |
-               (cx24123_readreg(state, 0x1d) << 8 |
-                cx24123_readreg(state, 0x1e));
-
-       dprintk("BER = %d\n", *ber);
-
+       *ber = fe->dtv_property_cache.error;
        return 0;
 }
 
 static int cx24123_read_signal_strength(struct dvb_frontend *fe,
        u16 *signal_strength)
 {
-       struct cx24123_state *state = fe->demodulator_priv;
-
-       /* larger = better */
-       *signal_strength = cx24123_readreg(state, 0x3b) << 8;
-
-       dprintk("Signal strength = %d\n", *signal_strength);
-
+       fe->dtv_property_cache.need_stats = FE_NEED_STRENGTH;
+       cx24123_get_stats(fe);
+       *signal_strength = fe->dtv_property_cache.strength;
        return 0;
 }
 
+
 static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr)
 {
-       struct cx24123_state *state = fe->demodulator_priv;
-
        /* Inverted raw Es/N0 count, totally bogus but better than the
-          BER threshold. */
-       *snr = 65535 - (((u16)cx24123_readreg(state, 0x18) << 8) |
-                        (u16)cx24123_readreg(state, 0x19));
-
-       dprintk("read S/N index = %d\n", *snr);
-
+               BER threshold. */
+       fe->dtv_property_cache.need_stats = FE_NEED_QUALITY;
+       cx24123_get_stats(fe);
+       *snr = fe->dtv_property_cache.quality;
        return 0;
 }
 
@@ -1174,6 +1221,7 @@ static struct dvb_frontend_ops cx24123_o
        .set_voltage = cx24123_set_voltage,
        .tune = cx24123_tune,
        .get_frontend_algo = cx24123_get_algo,
+       .get_stats = cx24123_get_stats,
 };
 
 MODULE_DESCRIPTION("DVB Frontend module for Conexant " \
diff --git a/linux/include/linux/dvb/frontend.h 
b/linux/include/linux/dvb/frontend.h
--- a/linux/include/linux/dvb/frontend.h
+++ b/linux/include/linux/dvb/frontend.h
@@ -304,7 +304,19 @@ struct dvb_frontend_event {
 
 #define DTV_ISDBS_TS_ID                42
 
-#define DTV_MAX_COMMAND                                DTV_ISDBS_TS_ID
+/* Quality parameters */
+#define DTV_FE_QUALITY         43
+#define DTV_FE_QUALITY_UNIT    44
+#define DTV_FE_STRENGTH                45
+#define DTV_FE_STRENGTH_UNIT   46
+#define DTV_FE_ERROR           47
+#define DTV_FE_ERROR_UNIT      48
+#define DTV_FE_SIGNAL          49
+#define DTV_FE_SIGNAL_UNIT     50
+#define DTV_FE_UNC             51
+#define DTV_FE_UNC_UNIT                52
+
+#define DTV_MAX_COMMAND                                DTV_FE_UNC_UNIT
 
 typedef enum fe_pilot {
        PILOT_ON,
@@ -338,6 +350,46 @@ typedef enum fe_delivery_system {
        SYS_DAB,
 } fe_delivery_system_t;
 
+/* Frontend General Statistics
+ * General parameters
+ * FE_*_UNKNOWN:
+ *     Parameter is unknown to the frontend and doesn't really
+ *     make any sense for an application.
+ *
+ * FE_*_RELATIVE:
+ *     Parameter is relative on the basis of a ceil - floor basis
+ *     Format is based on empirical test to determine
+ *     the floor and ceiling values. This format is exactly the
+ *     same format as the existing statistics implementation.
+ */
+
+enum fecap_quality_params {
+       FE_QUALITY_UNKNOWN              = 0,
+       FE_QUALITY_SNR                  = (1 <<  0),
+       FE_QUALITY_CNR                  = (1 <<  1),
+       FE_QUALITY_EsNo                 = (1 <<  2),
+       FE_QUALITY_EbNo                 = (1 <<  3),
+       FE_QUALITY_RELATIVE             = (1 << 31),
+};
+
+enum fecap_scale_params {
+       FE_SCALE_UNKNOWN                = 0,
+       FE_SCALE_dB                     = (1 <<  0),
+       FE_SCALE_RELATIVE               = (1 << 31),
+};
+
+enum fecap_error_params {
+       FE_ERROR_UNKNOWN                = 0,
+       FE_ERROR_BER                    = (1 <<  0),
+       FE_ERROR_PER                    = (1 <<  1),
+       FE_ERROR_RELATIVE               = (1 << 31),
+};
+
+enum fecap_unc_params {
+       FE_UNC_UNKNOWN                  = 0,
+       FE_UNC_RELATIVE                 = (1 << 31),
+};
+
 struct dtv_cmds_h {
        char    *name;          /* A display name for debugging purposes */
 
--
To unsubscribe from this list: send the line "unsubscribe linux-media" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to