Skip to content

Commit

Permalink
[media] af9015: fix i2c failures for dual-tuner devices
Browse files Browse the repository at this point in the history
The i2c failures were caused by enabling both i2c gates
at the same time while putting the tuners asleep.

This patch removes the init() and sleep() callbacks from the tuner,
to prevent frontend.c from calling
  i2c_gate_ctrl
  tuner init / sleep
  i2c_gate_ctrl
without holding the lock.
tuner init() and sleep() are instead called in frontend init() and
sleep().

Signed-off-by: Gordon Hecker <ghecker@gmx.de>
Signed-off-by: Antti Palosaari <crope@iki.fi>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Gordon Hecker authored and Mauro Carvalho Chehab committed Mar 19, 2012
1 parent d3db22e commit be4a5e7
Show file tree
Hide file tree
Showing 2 changed files with 33 additions and 0 deletions.
31 changes: 31 additions & 0 deletions drivers/media/dvb/dvb-usb/af9015.c
Original file line number Diff line number Diff line change
Expand Up @@ -1141,7 +1141,18 @@ static int af9015_af9013_init(struct dvb_frontend *fe)
return -EAGAIN;

ret = priv->init[adap->id](fe);
if (ret)
goto err_unlock;

if (priv->tuner_ops_init[adap->id]) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
ret = priv->tuner_ops_init[adap->id](fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
}

err_unlock:
mutex_unlock(&adap->dev->usb_mutex);

return ret;
Expand All @@ -1157,8 +1168,19 @@ static int af9015_af9013_sleep(struct dvb_frontend *fe)
if (mutex_lock_interruptible(&adap->dev->usb_mutex))
return -EAGAIN;

if (priv->tuner_ops_sleep[adap->id]) {
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
ret = priv->tuner_ops_sleep[adap->id](fe);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
if (ret)
goto err_unlock;
}

ret = priv->sleep[adap->id](fe);

err_unlock:
mutex_unlock(&adap->dev->usb_mutex);

return ret;
Expand Down Expand Up @@ -1283,6 +1305,7 @@ static struct mxl5007t_config af9015_mxl5007t_config = {
static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
{
int ret;
struct af9015_state *state = adap->dev->priv;
deb_info("%s:\n", __func__);

switch (af9015_af9013_config[adap->id].tuner) {
Expand Down Expand Up @@ -1340,6 +1363,14 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
err("Unknown tuner id:%d",
af9015_af9013_config[adap->id].tuner);
}

state->tuner_ops_sleep[adap->id] =
adap->fe_adap[0].fe->ops.tuner_ops.sleep;
adap->fe_adap[0].fe->ops.tuner_ops.sleep = 0;

state->tuner_ops_init[adap->id] =
adap->fe_adap[0].fe->ops.tuner_ops.init;
adap->fe_adap[0].fe->ops.tuner_ops.init = 0;
return ret;
}

Expand Down
2 changes: 2 additions & 0 deletions drivers/media/dvb/dvb-usb/af9015.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ struct af9015_state {
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);
int (*tuner_ops_init[2]) (struct dvb_frontend *fe);
int (*tuner_ops_sleep[2]) (struct dvb_frontend *fe);
};

struct af9015_config {
Expand Down

0 comments on commit be4a5e7

Please sign in to comment.