[media] dvb_frontend: Don't let drivers to trash data at cache
authorMauro Carvalho Chehab <mchehab@osg.samsung.com>
Thu, 4 Feb 2016 15:26:22 +0000 (13:26 -0200)
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>
Thu, 4 Feb 2016 18:27:41 +0000 (16:27 -0200)
GET_FRONTEND and G_PROPERTY can be called anytime, even when the
tuner/demod is not fully locked. However, several parameters
returned by those calls are available only after the demod get
VITERBI lock.

While several drivers do the right thing by checking the status before
returning the parameter, some drivers simply blindly update the
DTV properties cache without checking if the registers at the
hardware contain valid values.

Due to that, programs that call G_PROPERTY (or GET_FRONTEND)
before having a tuner lock may interfere at the zigzag logic,
as the DVB kthread calls the set_frontend() callback several
times, to fine tune the frequency and to identify if the signal
is inverted or not.

While the drivers should be fixed to report the right status,
we should prevent that such bugs would actually interfere at the
device operation.

So, let's use a separate var for userspace calls to get frontend.

As we copy the content of the cache, this should not cause any
troubles.

Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
drivers/media/dvb-core/dvb_frontend.c

index d009478f16c4e976d3ef1498244cf7e3aa0e487f..4c35eb47472bb7851472279dfa91e3b72b7fd2ca 100644 (file)
@@ -2087,6 +2087,8 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                        dev_dbg(fe->dvb->device, "%s: Property cache is full, tuning\n", __func__);
 
        } else if (cmd == FE_GET_PROPERTY) {
+               struct dtv_frontend_properties getp = fe->dtv_property_cache;
+
                dev_dbg(fe->dvb->device, "%s: properties.num = %d\n", __func__, tvps->num);
                dev_dbg(fe->dvb->device, "%s: properties.props = %p\n", __func__, tvps->props);
 
@@ -2108,17 +2110,18 @@ static int dvb_frontend_ioctl_properties(struct file *file,
                }
 
                /*
-                * Fills the cache out struct with the cache contents, plus
-                * the data retrieved from get_frontend, if the frontend
-                * is not idle. Otherwise, returns the cached content
+                * Let's use our own copy of property cache, in order to
+                * avoid mangling with DTV zigzag logic, as drivers might
+                * return crap, if they don't check if the data is available
+                * before updating the properties cache.
                 */
                if (fepriv->state != FESTATE_IDLE) {
-                       err = dtv_get_frontend(fe, c, NULL);
+                       err = dtv_get_frontend(fe, &getp, NULL);
                        if (err < 0)
                                goto out;
                }
                for (i = 0; i < tvps->num; i++) {
-                       err = dtv_property_process_get(fe, c, tvp + i, file);
+                       err = dtv_property_process_get(fe, &getp, tvp + i, file);
                        if (err < 0)
                                goto out;
                        (tvp + i)->result = err;
@@ -2523,10 +2526,18 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
                err = dvb_frontend_get_event (fe, parg, file->f_flags);
                break;
 
-       case FE_GET_FRONTEND:
-               err = dtv_get_frontend(fe, c, parg);
-               break;
+       case FE_GET_FRONTEND: {
+               struct dtv_frontend_properties getp = fe->dtv_property_cache;
 
+               /*
+                * Let's use our own copy of property cache, in order to
+                * avoid mangling with DTV zigzag logic, as drivers might
+                * return crap, if they don't check if the data is available
+                * before updating the properties cache.
+                */
+               err = dtv_get_frontend(fe, &getp, parg);
+               break;
+       }
        case FE_SET_FRONTEND_TUNE_MODE:
                fepriv->tune_mode_flags = (unsigned long) parg;
                err = 0;