Commit e90ab840 authored by Antti Palosaari's avatar Antti Palosaari Committed by Mauro Carvalho Chehab

[media] af9015: limit I2C access to keep FW happy

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: default avatarAntti Palosaari <crope@iki.fi>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent 6cf1056f
...@@ -1093,9 +1093,80 @@ static int af9015_rc_query(struct dvb_usb_device *d) ...@@ -1093,9 +1093,80 @@ static int af9015_rc_query(struct dvb_usb_device *d)
return ret; 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) static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
{ {
int ret; int ret;
struct af9015_state *state = adap->dev->priv;
if (adap->id == 1) { if (adap->id == 1) {
/* copy firmware to 2nd demodulator */ /* copy firmware to 2nd demodulator */
...@@ -1116,6 +1187,32 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap) ...@@ -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->fe_adap[0].fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
&adap->dev->i2c_adap); &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; return adap->fe_adap[0].fe == NULL ? -ENODEV : 0;
} }
......
...@@ -102,6 +102,13 @@ struct af9015_state { ...@@ -102,6 +102,13 @@ struct af9015_state {
u8 rc_repeat; u8 rc_repeat;
u32 rc_keycode; u32 rc_keycode;
u8 rc_last[4]; 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 { struct af9015_config {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment