Re: [patch] Fix AF9015 Dual tuner i2c write failures

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



>> Adding a "bus lock" to af9015_i2c_xfer() will not work as demod/tuner
>> accesses will take multiple i2c transactions.
>>
>> Therefore, the following patch overrides the dvb_frontend_ops
>> functions to add a per-device lock around them: only one frontend can
>> now use the i2c bus at a time. Testing with the scripts above shows
>> this has eliminated the errors.
>
> This have annoyed me too, but since it does not broken functionality much I
> haven't put much effort for fixing it. I like that fix since it is in AF9015
> driver where it logically belongs to. But it looks still rather complex. I
> see you have also considered "bus lock" to af9015_i2c_xfer() which could be
> much smaller in code size (that's I have tried to implement long time back).
>
> I would like to ask if it possible to check I2C gate open / close inside
> af9015_i2c_xfer() and lock according that? Something like:

Hmm, I did think about that, but I felt overriding the functions was
just cleaner: I felt it was more obvious what it was doing. Doing
exactly this sort of tweaking was one of the main reasons we added
that function overriding feature.

I don't like the idea of returning "error locked by FE" since that'll
mean the tuning will randomly fail sometimes in a way visible to
userspace (unless we change the core dvb_frontend code), which was one
of the things I was trying to avoid. Unless, of course, I've
misunderstood your proposal.

However, looking at the code again, I realise it is possible to
simplify it. Since its only the demod gates that cause a problem, we
only /actually/ need to lock the get_frontend() and set_frontend()
calls.

Signed-off-by: Andrew de Quincey <adq_dvb@xxxxxxxxxxxxx>
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 31c0a0e..52ac6ef 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -1083,6 +1083,34 @@ static int af9015_i2c_init(struct dvb_usb_device *d)
 	return ret;
 }
 
+static int af9015_lock_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	int result;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct af9015_state *state = adap->dev->priv;
+
+	if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+		return -EAGAIN;
+
+	result = state->fe_ops[adap->id].set_frontend(fe, params);
+	mutex_unlock(&adap->dev->usb_mutex);
+	return result;
+}
+                
+static int af9015_lock_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters* params)
+{
+	int result;
+	struct dvb_usb_adapter *adap = fe->dvb->priv;
+	struct af9015_state *state = adap->dev->priv;
+
+	if (mutex_lock_interruptible(&adap->dev->usb_mutex))
+		return -EAGAIN;
+
+	result = state->fe_ops[adap->id].get_frontend(fe, params);
+	mutex_unlock(&adap->dev->usb_mutex);
+	return result;
+}
+
 static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	int ret;
@@ -1116,6 +1144,12 @@ static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
 	/* attach demodulator */
 	adap->fe = dvb_attach(af9013_attach, &af9015_af9013_config[adap->id],
 		i2c_adap);
+		
+	memcpy(&state->fe_ops[adap->id], &adap->fe->ops, sizeof(struct dvb_frontend_ops));
+	if (adap->fe->ops.set_frontend)
+		adap->fe->ops.set_frontend = af9015_lock_set_frontend;
+	if (adap->fe->ops.get_frontend)
+		adap->fe->ops.get_frontend = af9015_lock_get_frontend;
 
 	return adap->fe == NULL ? -ENODEV : 0;
 }
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index f20cfa6..759bb3f 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -102,6 +102,7 @@ struct af9015_state {
 	struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
 	u8 rc_repeat;
 	u32 rc_keycode;
+	struct dvb_frontend_ops fe_ops[2];
 };
 
 struct af9015_config {

[Index of Archives]     [Linux Input]     [Video for Linux]     [Gstreamer Embedded]     [Mplayer Users]     [Linux USB Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [Yosemite Backpacking]
  Powered by Linux