]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
[media] af9015: limit I2C access to keep FW happy
authorAntti Palosaari <crope@iki.fi>
Sun, 13 Nov 2011 01:33:30 +0000 (22:33 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Fri, 30 Dec 2011 17:30:03 +0000 (15:30 -0200)
AF9015 firmware does not like if it gets interrupted by I2C adapter
request on some critical phases. During normal operation I2C adapter
is used only 2nd demodulator and tuner on dual tuner devices.

Override demodulator callbacks and use mutex for limit access to
those "critical" paths to keep AF9015 happy.

Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/dvb/dvb-usb/af9015.c
drivers/media/dvb/dvb-usb/af9015.h

index c6c275bac08e7e3c82cd9318b75ab789c0447ba6..033aa8affd8e06280fe66709034f066d2ae92cef 100644 (file)
@@ -1093,9 +1093,80 @@ error:
        return ret;
 }
 
+/* override demod callbacks for resource locking */
+static int af9015_af9013_set_frontend(struct dvb_frontend *fe,
+       struct dvb_frontend_parameters *params)
+{
+       int ret;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct af9015_state *priv = adap->dev->priv;
+
+       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+               return -EAGAIN;
+
+       ret = priv->set_frontend[adap->id](fe, params);
+
+       mutex_unlock(&adap->dev->usb_mutex);
+
+       return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_read_status(struct dvb_frontend *fe,
+       fe_status_t *status)
+{
+       int ret;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct af9015_state *priv = adap->dev->priv;
+
+       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+               return -EAGAIN;
+
+       ret = priv->read_status[adap->id](fe, status);
+
+       mutex_unlock(&adap->dev->usb_mutex);
+
+       return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_init(struct dvb_frontend *fe)
+{
+       int ret;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct af9015_state *priv = adap->dev->priv;
+
+       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+               return -EAGAIN;
+
+       ret = priv->init[adap->id](fe);
+
+       mutex_unlock(&adap->dev->usb_mutex);
+
+       return ret;
+}
+
+/* override demod callbacks for resource locking */
+static int af9015_af9013_sleep(struct dvb_frontend *fe)
+{
+       int ret;
+       struct dvb_usb_adapter *adap = fe->dvb->priv;
+       struct af9015_state *priv = adap->dev->priv;
+
+       if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+               return -EAGAIN;
+
+       ret = priv->init[adap->id](fe);
+
+       mutex_unlock(&adap->dev->usb_mutex);
+
+       return ret;
+}
+
 static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
 {
        int ret;
+       struct af9015_state *state = adap->dev->priv;
 
        if (adap->id == 1) {
                /* copy firmware to 2nd demodulator */
@@ -1116,6 +1187,32 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
        adap->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
                &adap->dev->i2c_adap);
 
+       /*
+        * AF9015 firmware does not like if it gets interrupted by I2C adapter
+        * request on some critical phases. During normal operation I2C adapter
+        * is used only 2nd demodulator and tuner on dual tuner devices.
+        * Override demodulator callbacks and use mutex for limit access to
+        * those "critical" paths to keep AF9015 happy.
+        * Note: we abuse unused usb_mutex here.
+        */
+       if (adap->fe_adap[0].fe) {
+               state->set_frontend[adap->id] =
+                       adap->fe_adap[0].fe->ops.set_frontend;
+               adap->fe_adap[0].fe->ops.set_frontend =
+                       af9015_af9013_set_frontend;
+
+               state->read_status[adap->id] =
+                       adap->fe_adap[0].fe->ops.read_status;
+               adap->fe_adap[0].fe->ops.read_status =
+                       af9015_af9013_read_status;
+
+               state->init[adap->id] = adap->fe_adap[0].fe->ops.init;
+               adap->fe_adap[0].fe->ops.init = af9015_af9013_init;
+
+               state->sleep[adap->id] = adap->fe_adap[0].fe->ops.sleep;
+               adap->fe_adap[0].fe->ops.sleep = af9015_af9013_sleep;
+       }
+
        return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
 }
 
index 6252ea6c19042b75a92e6aee88b3d9ec258f24da..4a126177e101dcbbc51165136596a91bda5bb5bc 100644 (file)
@@ -102,6 +102,13 @@ struct af9015_state {
        u8 rc_repeat;
        u32 rc_keycode;
        u8 rc_last[4];
+
+       /* for demod callback override */
+       int (*set_frontend[2]) (struct dvb_frontend *fe,
+               struct dvb_frontend_parameters *params);
+       int (*read_status[2]) (struct dvb_frontend *fe, fe_status_t *status);
+       int (*init[2]) (struct dvb_frontend *fe);
+       int (*sleep[2]) (struct dvb_frontend *fe);
 };
 
 struct af9015_config {