public inbox for linux-media@vger.kernel.org
 help / color / mirror / Atom feed
* [patch] Fix AF9015 Dual tuner i2c write failures
@ 2011-03-04 21:37 Andrew de Quincey
  2011-03-04 22:13 ` Antti Palosaari
  0 siblings, 1 reply; 31+ messages in thread
From: Andrew de Quincey @ 2011-03-04 21:37 UTC (permalink / raw)
  To: linux-media

[-- Attachment #1: Type: text/plain, Size: 1557 bytes --]

Hi, this has been annoying me for some time, so this evening I fixed
it. If you use one of the above dual tuner devices (e.g. KWorld 399U),
you get random tuning failures and i2c errors reported in dmesg such
as:

af9013: I2C read failed reg:d607
af9015: command failed:1
mxl5005s I2C write failed
af9015: command failed:1
mxl5005s I2C write failed
af9015: command failed:2
af9013: I2C read failed reg:d607
af9015: command failed:2
af9013: I2C read failed reg:d607

Looking at the large comment in dvb-usb/af9015.c/af9015_i2c_xfer() it
seems the dual demods/tuners have the same i2c addresses and are
switched by an i2c gate. Since the two show up as separate DVB
devices, and there is no synchronisation of i2c accesses, its fairly
obvious the problem is because both tuners are being written to at the
same time, which is mucking up the i2c gate. I tested this with two
scripts on my development machine:

while [ 1 ];
do
        scan -a 0 /usr/share/dvb/dvb-t/uk-Craigkelly
done

AND

while [ 1 ];
do
        scan -a 1 /usr/share/dvb/dvb-t/uk-Craigkelly
done


If I run only one at a time, it works perfectly. Run two, and I start
to see errors.

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.

Signed-off-by: Andrew de Quincey <adq_dvb@lidskialf.net>

[-- Attachment #2: af9015-fix-dual-tuner-v1.patch --]
[-- Type: text/x-patch, Size: 4579 bytes --]

diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 31c0a0e..740d969 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -1083,6 +1083,104 @@ 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_lock_read_status(struct dvb_frontend* fe, fe_status_t* status)
+{
+	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].read_status(fe, status);
+	mutex_unlock(&adap->dev->usb_mutex);
+	return result;
+}
+
+static int af9015_lock_read_ber(struct dvb_frontend* fe, u32* ber)
+{
+	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].read_ber(fe, ber);
+	mutex_unlock(&adap->dev->usb_mutex);
+	return result;
+}
+
+static int af9015_lock_read_signal_strength(struct dvb_frontend* fe, u16* strength)
+{
+	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].read_signal_strength(fe, strength);
+	mutex_unlock(&adap->dev->usb_mutex);
+	return result;
+}
+
+static int af9015_lock_read_snr(struct dvb_frontend* fe, u16* snr)
+{
+	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].read_snr(fe, snr);
+	mutex_unlock(&adap->dev->usb_mutex);
+	return result;
+}
+
+static int af9015_lock_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
+{
+	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].read_ucblocks(fe, ucblocks);
+	mutex_unlock(&adap->dev->usb_mutex);
+	return result;
+}
+
 static int af9015_af9013_frontend_attach(struct dvb_usb_adapter *adap)
 {
 	int ret;
@@ -1116,6 +1214,22 @@ 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;
+	if (adap->fe->ops.read_status)
+		adap->fe->ops.read_status = af9015_lock_read_status;
+	if (adap->fe->ops.read_ber)
+		adap->fe->ops.read_ber = af9015_lock_read_ber;
+	if (adap->fe->ops.read_signal_strength)
+		adap->fe->ops.read_signal_strength = af9015_lock_read_signal_strength;
+	if (adap->fe->ops.read_snr)
+		adap->fe->ops.read_snr = af9015_lock_read_snr;
+	if (adap->fe->ops.read_ucblocks)
+		adap->fe->ops.read_ucblocks = af9015_lock_read_ucblocks;
 
 	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 {

^ permalink raw reply related	[flat|nested] 31+ messages in thread

end of thread, other threads:[~2011-04-02 17:24 UTC | newest]

Thread overview: 31+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-03-04 21:37 [patch] Fix AF9015 Dual tuner i2c write failures Andrew de Quincey
2011-03-04 22:13 ` Antti Palosaari
2011-03-04 22:44   ` Andrew de Quincey
2011-03-04 22:59     ` Antti Palosaari
2011-03-04 23:11       ` Andrew de Quincey
2011-03-05  1:43         ` adq
2011-03-05  1:51           ` adq
     [not found]             ` <AANLkTi=YMtTbgwxNA1O6zp03OoeGKJvn8oYDB9kHjti1@mail.gmail.com>
2011-03-05  9:23               ` Antti Palosaari
2011-03-05 11:56                 ` Andrew de Quincey
2011-03-05 11:55               ` adq
2011-03-06 11:56                 ` adq
2011-03-06 12:24                   ` adq
2011-03-06 13:04                     ` Antti Palosaari
2011-03-06 13:08                       ` adq
2011-03-06 13:24                         ` adq
2011-03-07 18:26                   ` adq
2011-03-07 22:12                     ` adq
2011-03-18 15:46                       ` Antti Palosaari
2011-03-21 20:11                         ` adq
2011-04-02  1:24                         ` adq
2011-04-02  8:20                           ` Antti Palosaari
2011-04-02 11:06                             ` adq
2011-04-02 11:15                               ` adq
2011-04-02 12:18                               ` Antti Palosaari
2011-04-02 13:45                                 ` adq
2011-04-02 17:24                                   ` Antti Palosaari
2011-03-05  9:56             ` Antti Palosaari
2011-03-05 10:49           ` Antti Palosaari
2011-03-22  9:00         ` Mauro Carvalho Chehab
2011-03-22 18:26           ` adq
2011-03-22 18:36             ` Mauro Carvalho Chehab

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox