[kernel] Backport 3 fixed from linux-next to fix dib0700 playback (rhbz 733827)

Josh Boyer jwboyer at fedoraproject.org
Mon Oct 24 13:12:54 UTC 2011


commit e78653bd39151e19f8f24a67dc56f446f452e516
Author: Josh Boyer <jwboyer at redhat.com>
Date:   Mon Oct 24 09:01:53 2011 -0400

    Backport 3 fixed from linux-next to fix dib0700 playback (rhbz 733827)

 kernel.spec                                        |   13 +-
 media-DiBcom-protect-the-I2C-bufer-access.patch    | 1150 ++++++++++++++++++++
 media-dib0700-correct-error-message.patch          |  103 ++
 ...dib0700-protect-the-dib0700-buffer-access.patch |  248 +++++
 4 files changed, 1513 insertions(+), 1 deletions(-)
---
diff --git a/kernel.spec b/kernel.spec
index 8de9ac7..96984b7 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -51,7 +51,7 @@ Summary: The Linux kernel
 # For non-released -rc kernels, this will be prepended with "0.", so
 # for example a 3 here will become 0.3
 #
-%global baserelease 1
+%global baserelease 2
 %global fedora_build %{baserelease}
 
 # base_sublevel is the kernel version we're starting with and patching
@@ -706,6 +706,10 @@ Patch2899: linux-2.6-v4l-dvb-fixes.patch
 Patch2900: linux-2.6-v4l-dvb-update.patch
 Patch2901: linux-2.6-v4l-dvb-experimental.patch
 
+Patch2903: media-DiBcom-protect-the-I2C-bufer-access.patch
+Patch2904: media-dib0700-protect-the-dib0700-buffer-access.patch
+Patch2905: media-dib0700-correct-error-message.patch
+
 Patch3000: rcutree-avoid-false-quiescent-states.patch
 
 # fs fixes
@@ -1381,6 +1385,10 @@ ApplyPatch iwlagn-fix-ht_params-NULL-pointer-dereference.patch
 #rhbz #722509
 ApplyPatch mmc-Always-check-for-lower-base-frequency-quirk-for-.patch
 
+ApplyPatch media-DiBcom-protect-the-I2C-bufer-access.patch
+ApplyPatch media-dib0700-protect-the-dib0700-buffer-access.patch
+ApplyPatch media-dib0700-correct-error-message.patch
+
 # utrace.
 ApplyPatch utrace.patch
 
@@ -2096,6 +2104,9 @@ fi
 #                 ||----w |
 #                 ||     ||
 %changelog
+* Mon Oct 24 2011 Josh Boyer <jwboyer at redhat.com>
+- Backport 3 fixed from linux-next to fix dib0700 playback (rhbz 733827)
+
 * Mon Oct 24 2011 Chuck Ebbert <cebbert at redhat.com> 3.1.0-1
 - Linux 3.1
 
diff --git a/media-DiBcom-protect-the-I2C-bufer-access.patch b/media-DiBcom-protect-the-I2C-bufer-access.patch
new file mode 100644
index 0000000..1b2a54b
--- /dev/null
+++ b/media-DiBcom-protect-the-I2C-bufer-access.patch
@@ -0,0 +1,1150 @@
+From: Patrick Boettcher <Patrick.Boettcher at dibcom.fr>
+Date: Wed, 3 Aug 2011 15:08:21 +0000 (-0300)
+Subject: [media] DiBcom: protect the I2C bufer access
+X-Git-Tag: next-20110927~67^2~4^2~225
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fnext%2Flinux-next.git;a=commitdiff_plain;h=79fcce3230b140f7675f8529ee53fe2f9644f902
+
+[media] DiBcom: protect the I2C bufer access
+
+This patch protects the I2C buffer access in order to manage concurrent
+access. This protection is done using mutex.
+Furthermore, for the dib9000, if a pid filtering command is
+received during the tuning, this pid filtering command is delayed to
+avoid any concurrent access issue.
+
+Cc: Mauro Carvalho Chehab <mchehab at redhat.com>
+Cc: Florian Mickler <florian at mickler.org>
+Cc: stable at kernel.org
+Signed-off-by: Olivier Grenie <olivier.grenie at dibcom.fr>
+Signed-off-by: Patrick Boettcher <Patrick.Boettcher at dibcom.fr>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+
+diff --git a/drivers/media/dvb/frontends/dib0070.c b/drivers/media/dvb/frontends/dib0070.c
+index 1d47d4d..dc1cb17 100644
+--- a/drivers/media/dvb/frontends/dib0070.c
++++ b/drivers/media/dvb/frontends/dib0070.c
+@@ -27,6 +27,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+ 
+ #include "dvb_frontend.h"
+ 
+@@ -78,10 +79,18 @@ struct dib0070_state {
+ 	struct i2c_msg msg[2];
+ 	u8 i2c_write_buffer[3];
+ 	u8 i2c_read_buffer[2];
++	struct mutex i2c_buffer_lock;
+ };
+ 
+-static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
++static u16 dib0070_read_reg(struct dib0070_state *state, u8 reg)
+ {
++	u16 ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return 0;
++	}
++
+ 	state->i2c_write_buffer[0] = reg;
+ 
+ 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+@@ -96,13 +105,23 @@ static uint16_t dib0070_read_reg(struct dib0070_state *state, u8 reg)
+ 
+ 	if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
+ 		printk(KERN_WARNING "DiB0070 I2C read failed\n");
+-		return 0;
+-	}
+-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++		ret = 0;
++	} else
++		ret = (state->i2c_read_buffer[0] << 8)
++			| state->i2c_read_buffer[1];
++
++	mutex_unlock(&state->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+ {
++	int ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
+ 	state->i2c_write_buffer[0] = reg;
+ 	state->i2c_write_buffer[1] = val >> 8;
+ 	state->i2c_write_buffer[2] = val & 0xff;
+@@ -115,9 +134,12 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val)
+ 
+ 	if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
+ 		printk(KERN_WARNING "DiB0070 I2C write failed\n");
+-		return -EREMOTEIO;
+-	}
+-	return 0;
++		ret = -EREMOTEIO;
++	} else
++		ret = 0;
++
++	mutex_unlock(&state->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ #define HARD_RESET(state) do { \
+@@ -734,6 +756,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter
+ 	state->cfg = cfg;
+ 	state->i2c = i2c;
+ 	state->fe  = fe;
++	mutex_init(&state->i2c_buffer_lock);
+ 	fe->tuner_priv = state;
+ 
+ 	if (dib0070_reset(fe) != 0)
+diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c
+index c9c935a..b174d1c 100644
+--- a/drivers/media/dvb/frontends/dib0090.c
++++ b/drivers/media/dvb/frontends/dib0090.c
+@@ -27,6 +27,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+ 
+ #include "dvb_frontend.h"
+ 
+@@ -196,6 +197,7 @@ struct dib0090_state {
+ 	struct i2c_msg msg[2];
+ 	u8 i2c_write_buffer[3];
+ 	u8 i2c_read_buffer[2];
++	struct mutex i2c_buffer_lock;
+ };
+ 
+ struct dib0090_fw_state {
+@@ -208,10 +210,18 @@ struct dib0090_fw_state {
+ 	struct i2c_msg msg;
+ 	u8 i2c_write_buffer[2];
+ 	u8 i2c_read_buffer[2];
++	struct mutex i2c_buffer_lock;
+ };
+ 
+ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
+ {
++	u16 ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return 0;
++	}
++
+ 	state->i2c_write_buffer[0] = reg;
+ 
+ 	memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
+@@ -226,14 +236,24 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
+ 
+ 	if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
+ 		printk(KERN_WARNING "DiB0090 I2C read failed\n");
+-		return 0;
+-	}
++		ret = 0;
++	} else
++		ret = (state->i2c_read_buffer[0] << 8)
++			| state->i2c_read_buffer[1];
+ 
+-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++	mutex_unlock(&state->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
+ {
++	int ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
++
+ 	state->i2c_write_buffer[0] = reg & 0xff;
+ 	state->i2c_write_buffer[1] = val >> 8;
+ 	state->i2c_write_buffer[2] = val & 0xff;
+@@ -246,13 +266,23 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val)
+ 
+ 	if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
+ 		printk(KERN_WARNING "DiB0090 I2C write failed\n");
+-		return -EREMOTEIO;
+-	}
+-	return 0;
++		ret = -EREMOTEIO;
++	} else
++		ret = 0;
++
++	mutex_unlock(&state->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
+ {
++	u16 ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return 0;
++	}
++
+ 	state->i2c_write_buffer[0] = reg;
+ 
+ 	memset(&state->msg, 0, sizeof(struct i2c_msg));
+@@ -262,13 +292,24 @@ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
+ 	state->msg.len = 2;
+ 	if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
+ 		printk(KERN_WARNING "DiB0090 I2C read failed\n");
+-		return 0;
+-	}
+-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++		ret = 0;
++	} else
++		ret = (state->i2c_read_buffer[0] << 8)
++			| state->i2c_read_buffer[1];
++
++	mutex_unlock(&state->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
+ {
++	int ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
++
+ 	state->i2c_write_buffer[0] = val >> 8;
+ 	state->i2c_write_buffer[1] = val & 0xff;
+ 
+@@ -279,9 +320,12 @@ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
+ 	state->msg.len = 2;
+ 	if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
+ 		printk(KERN_WARNING "DiB0090 I2C write failed\n");
+-		return -EREMOTEIO;
+-	}
+-	return 0;
++		ret = -EREMOTEIO;
++	} else
++		ret = 0;
++
++	mutex_unlock(&state->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ #define HARD_RESET(state) do {  if (cfg->reset) {  if (cfg->sleep) cfg->sleep(fe, 0); msleep(10);  cfg->reset(fe, 1); msleep(10);  cfg->reset(fe, 0); msleep(10);  }  } while (0)
+@@ -2440,6 +2484,7 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte
+ 	st->config = config;
+ 	st->i2c = i2c;
+ 	st->fe = fe;
++	mutex_init(&st->i2c_buffer_lock);
+ 	fe->tuner_priv = st;
+ 
+ 	if (config->wbd == NULL)
+@@ -2471,6 +2516,7 @@ struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_ada
+ 	st->config = config;
+ 	st->i2c = i2c;
+ 	st->fe = fe;
++	mutex_init(&st->i2c_buffer_lock);
+ 	fe->tuner_priv = st;
+ 
+ 	if (dib0090_fw_reset_digital(fe, st->config) != 0)
+diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
+index 79cb1c2..dbb76d7 100644
+--- a/drivers/media/dvb/frontends/dib7000m.c
++++ b/drivers/media/dvb/frontends/dib7000m.c
+@@ -11,6 +11,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+ 
+ #include "dvb_frontend.h"
+ 
+@@ -55,6 +56,7 @@ struct dib7000m_state {
+ 	struct i2c_msg msg[2];
+ 	u8 i2c_write_buffer[4];
+ 	u8 i2c_read_buffer[2];
++	struct mutex i2c_buffer_lock;
+ };
+ 
+ enum dib7000m_power_mode {
+@@ -69,6 +71,13 @@ enum dib7000m_power_mode {
+ 
+ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
+ {
++	u16 ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return 0;
++	}
++
+ 	state->i2c_write_buffer[0] = (reg >> 8) | 0x80;
+ 	state->i2c_write_buffer[1] = reg & 0xff;
+ 
+@@ -85,11 +94,21 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg)
+ 	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
+ 		dprintk("i2c read error on %d",reg);
+ 
+-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++	mutex_unlock(&state->i2c_buffer_lock);
++
++	return ret;
+ }
+ 
+ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
+ {
++	int ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
++
+ 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ 	state->i2c_write_buffer[1] = reg & 0xff;
+ 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -101,7 +120,10 @@ static int dib7000m_write_word(struct dib7000m_state *state, u16 reg, u16 val)
+ 	state->msg[0].buf = state->i2c_write_buffer;
+ 	state->msg[0].len = 4;
+ 
+-	return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
++			-EREMOTEIO : 0);
++	mutex_unlock(&state->i2c_buffer_lock);
++	return ret;
+ }
+ static void dib7000m_write_tab(struct dib7000m_state *state, u16 *buf)
+ {
+@@ -1385,6 +1407,7 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
+ 	demod                   = &st->demod;
+ 	demod->demodulator_priv = st;
+ 	memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
++	mutex_init(&st->i2c_buffer_lock);
+ 
+ 	st->timf_default = cfg->bw->timf;
+ 
+diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
+index a64a538..4eb9c2b 100644
+--- a/drivers/media/dvb/frontends/dib7000p.c
++++ b/drivers/media/dvb/frontends/dib7000p.c
+@@ -10,6 +10,7 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+ 
+ #include "dvb_math.h"
+ #include "dvb_frontend.h"
+@@ -68,6 +69,7 @@ struct dib7000p_state {
+ 	struct i2c_msg msg[2];
+ 	u8 i2c_write_buffer[4];
+ 	u8 i2c_read_buffer[2];
++	struct mutex i2c_buffer_lock;
+ };
+ 
+ enum dib7000p_power_mode {
+@@ -81,6 +83,13 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff);
+ 
+ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
+ {
++	u16 ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return 0;
++	}
++
+ 	state->i2c_write_buffer[0] = reg >> 8;
+ 	state->i2c_write_buffer[1] = reg & 0xff;
+ 
+@@ -97,11 +106,20 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg)
+ 	if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
+ 		dprintk("i2c read error on %d", reg);
+ 
+-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++	mutex_unlock(&state->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
+ {
++	int ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
++
+ 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ 	state->i2c_write_buffer[1] = reg & 0xff;
+ 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -113,7 +131,10 @@ static int dib7000p_write_word(struct dib7000p_state *state, u16 reg, u16 val)
+ 	state->msg[0].buf = state->i2c_write_buffer;
+ 	state->msg[0].len = 4;
+ 
+-	return i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++	ret = (i2c_transfer(state->i2c_adap, state->msg, 1) != 1 ?
++			-EREMOTEIO : 0);
++	mutex_unlock(&state->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ static void dib7000p_write_tab(struct dib7000p_state *state, u16 * buf)
+@@ -1646,6 +1667,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
+ 		return -ENOMEM;
+ 
+ 	dpst->i2c_adap = i2c;
++	mutex_init(&dpst->i2c_buffer_lock);
+ 
+ 	for (k = no_of_demods - 1; k >= 0; k--) {
+ 		dpst->cfg = cfg[k];
+@@ -2324,6 +2346,7 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
+ 	demod = &st->demod;
+ 	demod->demodulator_priv = st;
+ 	memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops));
++	mutex_init(&st->i2c_buffer_lock);
+ 
+ 	dib7000p_write_word(st, 1287, 0x0003);	/* sram lead in, rdy */
+ 
+@@ -2333,8 +2356,9 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
+ 	st->version = dib7000p_read_word(st, 897);
+ 
+ 	/* FIXME: make sure the dev.parent field is initialized, or else
+-		request_firmware() will hit an OOPS (this should be moved somewhere
+-		more common) */
++	   request_firmware() will hit an OOPS (this should be moved somewhere
++	   more common) */
++	st->i2c_master.gated_tuner_i2c_adap.dev.parent = i2c_adap->dev.parent;
+ 
+ 	/* FIXME: make sure the dev.parent field is initialized, or else
+ 	   request_firmware() will hit an OOPS (this should be moved somewhere
+diff --git a/drivers/media/dvb/frontends/dib8000.c b/drivers/media/dvb/frontends/dib8000.c
+index 7d2ea11..fe284d5 100644
+--- a/drivers/media/dvb/frontends/dib8000.c
++++ b/drivers/media/dvb/frontends/dib8000.c
+@@ -10,6 +10,8 @@
+ #include <linux/kernel.h>
+ #include <linux/slab.h>
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
++
+ #include "dvb_math.h"
+ 
+ #include "dvb_frontend.h"
+@@ -37,6 +39,7 @@ struct i2c_device {
+ 	u8 addr;
+ 	u8 *i2c_write_buffer;
+ 	u8 *i2c_read_buffer;
++	struct mutex *i2c_buffer_lock;
+ };
+ 
+ struct dib8000_state {
+@@ -77,6 +80,7 @@ struct dib8000_state {
+ 	struct i2c_msg msg[2];
+ 	u8 i2c_write_buffer[4];
+ 	u8 i2c_read_buffer[2];
++	struct mutex i2c_buffer_lock;
+ };
+ 
+ enum dib8000_power_mode {
+@@ -86,24 +90,39 @@ enum dib8000_power_mode {
+ 
+ static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
+ {
++	u16 ret;
+ 	struct i2c_msg msg[2] = {
+-		{.addr = i2c->addr >> 1, .flags = 0,
+-			.buf = i2c->i2c_write_buffer, .len = 2},
+-		{.addr = i2c->addr >> 1, .flags = I2C_M_RD,
+-			.buf = i2c->i2c_read_buffer, .len = 2},
++		{.addr = i2c->addr >> 1, .flags = 0, .len = 2},
++		{.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
+ 	};
+ 
++	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return 0;
++	}
++
++	msg[0].buf    = i2c->i2c_write_buffer;
+ 	msg[0].buf[0] = reg >> 8;
+ 	msg[0].buf[1] = reg & 0xff;
++	msg[1].buf    = i2c->i2c_read_buffer;
+ 
+ 	if (i2c_transfer(i2c->adap, msg, 2) != 2)
+ 		dprintk("i2c read error on %d", reg);
+ 
+-	return (msg[1].buf[0] << 8) | msg[1].buf[1];
++	ret = (msg[1].buf[0] << 8) | msg[1].buf[1];
++	mutex_unlock(i2c->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
+ {
++	u16 ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return 0;
++	}
++
+ 	state->i2c_write_buffer[0] = reg >> 8;
+ 	state->i2c_write_buffer[1] = reg & 0xff;
+ 
+@@ -120,7 +139,10 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg)
+ 	if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
+ 		dprintk("i2c read error on %d", reg);
+ 
+-	return (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++	ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1];
++	mutex_unlock(&state->i2c_buffer_lock);
++
++	return ret;
+ }
+ 
+ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
+@@ -135,22 +157,35 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
+ 
+ static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
+ {
+-	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0,
+-		.buf = i2c->i2c_write_buffer, .len = 4};
++	struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
+ 	int ret = 0;
+ 
++	if (mutex_lock_interruptible(i2c->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
++
++	msg.buf    = i2c->i2c_write_buffer;
+ 	msg.buf[0] = (reg >> 8) & 0xff;
+ 	msg.buf[1] = reg & 0xff;
+ 	msg.buf[2] = (val >> 8) & 0xff;
+ 	msg.buf[3] = val & 0xff;
+ 
+ 	ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
++	mutex_unlock(i2c->i2c_buffer_lock);
+ 
+ 	return ret;
+ }
+ 
+ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
+ {
++	int ret;
++
++	if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
++
+ 	state->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ 	state->i2c_write_buffer[1] = reg & 0xff;
+ 	state->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -162,7 +197,11 @@ static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val)
+ 	state->msg[0].buf = state->i2c_write_buffer;
+ 	state->msg[0].len = 4;
+ 
+-	return i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ? -EREMOTEIO : 0;
++	ret = (i2c_transfer(state->i2c.adap, state->msg, 1) != 1 ?
++			-EREMOTEIO : 0);
++	mutex_unlock(&state->i2c_buffer_lock);
++
++	return ret;
+ }
+ 
+ static const s16 coeff_2k_sb_1seg_dqpsk[8] = {
+@@ -2434,8 +2473,15 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
+ 	if (!client.i2c_read_buffer) {
+ 		dprintk("%s: not enough memory", __func__);
+ 		ret = -ENOMEM;
+-		goto error_memory;
++		goto error_memory_read;
++	}
++	client.i2c_buffer_lock = kzalloc(sizeof(struct mutex), GFP_KERNEL);
++	if (!client.i2c_buffer_lock) {
++		dprintk("%s: not enough memory", __func__);
++		ret = -ENOMEM;
++		goto error_memory_lock;
+ 	}
++	mutex_init(client.i2c_buffer_lock);
+ 
+ 	for (k = no_of_demods - 1; k >= 0; k--) {
+ 		/* designated i2c address */
+@@ -2476,8 +2522,10 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
+ 	}
+ 
+ error:
++	kfree(client.i2c_buffer_lock);
++error_memory_lock:
+ 	kfree(client.i2c_read_buffer);
+-error_memory:
++error_memory_read:
+ 	kfree(client.i2c_write_buffer);
+ 
+ 	return ret;
+@@ -2581,6 +2629,8 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s
+ 	state->i2c.addr = i2c_addr;
+ 	state->i2c.i2c_write_buffer = state->i2c_write_buffer;
+ 	state->i2c.i2c_read_buffer = state->i2c_read_buffer;
++	mutex_init(&state->i2c_buffer_lock);
++	state->i2c.i2c_buffer_lock = &state->i2c_buffer_lock;
+ 	state->gpio_val = cfg->gpio_val;
+ 	state->gpio_dir = cfg->gpio_dir;
+ 
+diff --git a/drivers/media/dvb/frontends/dib9000.c b/drivers/media/dvb/frontends/dib9000.c
+index a085588..b931074 100644
+--- a/drivers/media/dvb/frontends/dib9000.c
++++ b/drivers/media/dvb/frontends/dib9000.c
+@@ -38,6 +38,15 @@ struct i2c_device {
+ #define DibInitLock(lock) mutex_init(lock)
+ #define DibFreeLock(lock)
+ 
++struct dib9000_pid_ctrl {
++#define DIB9000_PID_FILTER_CTRL 0
++#define DIB9000_PID_FILTER      1
++	u8 cmd;
++	u8 id;
++	u16 pid;
++	u8 onoff;
++};
++
+ struct dib9000_state {
+ 	struct i2c_device i2c;
+ 
+@@ -99,6 +108,10 @@ struct dib9000_state {
+ 	struct i2c_msg msg[2];
+ 	u8 i2c_write_buffer[255];
+ 	u8 i2c_read_buffer[255];
++	DIB_LOCK demod_lock;
++	u8 get_frontend_internal;
++	struct dib9000_pid_ctrl pid_ctrl[10];
++	s8 pid_ctrl_index; /* -1: empty list; -2: do not use the list */
+ };
+ 
+ static const u32 fe_info[44] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+@@ -1743,19 +1756,56 @@ EXPORT_SYMBOL(dib9000_set_gpio);
+ int dib9000_fw_pid_filter_ctrl(struct dvb_frontend *fe, u8 onoff)
+ {
+ 	struct dib9000_state *state = fe->demodulator_priv;
+-	u16 val = dib9000_read_word(state, 294 + 1) & 0xffef;
++	u16 val;
++	int ret;
++
++	if ((state->pid_ctrl_index != -2) && (state->pid_ctrl_index < 9)) {
++		/* postpone the pid filtering cmd */
++		dprintk("pid filter cmd postpone");
++		state->pid_ctrl_index++;
++		state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER_CTRL;
++		state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
++		return 0;
++	}
++
++	DibAcquireLock(&state->demod_lock);
++
++	val = dib9000_read_word(state, 294 + 1) & 0xffef;
+ 	val |= (onoff & 0x1) << 4;
+ 
+ 	dprintk("PID filter enabled %d", onoff);
+-	return dib9000_write_word(state, 294 + 1, val);
++	ret = dib9000_write_word(state, 294 + 1, val);
++	DibReleaseLock(&state->demod_lock);
++	return ret;
++
+ }
+ EXPORT_SYMBOL(dib9000_fw_pid_filter_ctrl);
+ 
+ int dib9000_fw_pid_filter(struct dvb_frontend *fe, u8 id, u16 pid, u8 onoff)
+ {
+ 	struct dib9000_state *state = fe->demodulator_priv;
++	int ret;
++
++	if (state->pid_ctrl_index != -2) {
++		/* postpone the pid filtering cmd */
++		dprintk("pid filter postpone");
++		if (state->pid_ctrl_index < 9) {
++			state->pid_ctrl_index++;
++			state->pid_ctrl[state->pid_ctrl_index].cmd = DIB9000_PID_FILTER;
++			state->pid_ctrl[state->pid_ctrl_index].id = id;
++			state->pid_ctrl[state->pid_ctrl_index].pid = pid;
++			state->pid_ctrl[state->pid_ctrl_index].onoff = onoff;
++		} else
++			dprintk("can not add any more pid ctrl cmd");
++		return 0;
++	}
++
++	DibAcquireLock(&state->demod_lock);
+ 	dprintk("Index %x, PID %d, OnOff %d", id, pid, onoff);
+-	return dib9000_write_word(state, 300 + 1 + id, onoff ? (1 << 13) | pid : 0);
++	ret = dib9000_write_word(state, 300 + 1 + id,
++			onoff ? (1 << 13) | pid : 0);
++	DibReleaseLock(&state->demod_lock);
++	return ret;
+ }
+ EXPORT_SYMBOL(dib9000_fw_pid_filter);
+ 
+@@ -1778,6 +1828,7 @@ static void dib9000_release(struct dvb_frontend *demod)
+ 	DibFreeLock(&state->platform.risc.mbx_lock);
+ 	DibFreeLock(&state->platform.risc.mem_lock);
+ 	DibFreeLock(&state->platform.risc.mem_mbx_lock);
++	DibFreeLock(&state->demod_lock);
+ 	dibx000_exit_i2c_master(&st->i2c_master);
+ 
+ 	i2c_del_adapter(&st->tuner_adap);
+@@ -1795,14 +1846,19 @@ static int dib9000_sleep(struct dvb_frontend *fe)
+ {
+ 	struct dib9000_state *state = fe->demodulator_priv;
+ 	u8 index_frontend;
+-	int ret;
++	int ret = 0;
+ 
++	DibAcquireLock(&state->demod_lock);
+ 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+ 		ret = state->fe[index_frontend]->ops.sleep(state->fe[index_frontend]);
+ 		if (ret < 0)
+-			return ret;
++			goto error;
+ 	}
+-	return dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
++	ret = dib9000_mbx_send(state, OUT_MSG_FE_SLEEP, NULL, 0);
++
++error:
++	DibReleaseLock(&state->demod_lock);
++	return ret;
+ }
+ 
+ static int dib9000_fe_get_tune_settings(struct dvb_frontend *fe, struct dvb_frontend_tune_settings *tune)
+@@ -1816,7 +1872,10 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
+ 	struct dib9000_state *state = fe->demodulator_priv;
+ 	u8 index_frontend, sub_index_frontend;
+ 	fe_status_t stat;
+-	int ret;
++	int ret = 0;
++
++	if (state->get_frontend_internal == 0)
++		DibAcquireLock(&state->demod_lock);
+ 
+ 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+ 		state->fe[index_frontend]->ops.read_status(state->fe[index_frontend], &stat);
+@@ -1846,14 +1905,15 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
+ 					    state->fe[index_frontend]->dtv_property_cache.rolloff;
+ 				}
+ 			}
+-			return 0;
++			ret = 0;
++			goto return_value;
+ 		}
+ 	}
+ 
+ 	/* get the channel from master chip */
+ 	ret = dib9000_fw_get_channel(fe, fep);
+ 	if (ret != 0)
+-		return ret;
++		goto return_value;
+ 
+ 	/* synchronize the cache with the other frontends */
+ 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+@@ -1866,8 +1926,12 @@ static int dib9000_get_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
+ 		state->fe[index_frontend]->dtv_property_cache.code_rate_LP = fe->dtv_property_cache.code_rate_LP;
+ 		state->fe[index_frontend]->dtv_property_cache.rolloff = fe->dtv_property_cache.rolloff;
+ 	}
++	ret = 0;
+ 
+-	return 0;
++return_value:
++	if (state->get_frontend_internal == 0)
++		DibReleaseLock(&state->demod_lock);
++	return ret;
+ }
+ 
+ static int dib9000_set_tune_state(struct dvb_frontend *fe, enum frontend_tune_state tune_state)
+@@ -1912,6 +1976,10 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
+ 		dprintk("dib9000: must specify bandwidth ");
+ 		return 0;
+ 	}
++
++	state->pid_ctrl_index = -1; /* postpone the pid filtering cmd */
++	DibAcquireLock(&state->demod_lock);
++
+ 	fe->dtv_property_cache.delivery_system = SYS_DVBT;
+ 
+ 	/* set the master status */
+@@ -1974,13 +2042,18 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
+ 	/* check the tune result */
+ 	if (exit_condition == 1) {	/* tune failed */
+ 		dprintk("tune failed");
++		DibReleaseLock(&state->demod_lock);
++		/* tune failed; put all the pid filtering cmd to junk */
++		state->pid_ctrl_index = -1;
+ 		return 0;
+ 	}
+ 
+ 	dprintk("tune success on frontend%i", index_frontend_success);
+ 
+ 	/* synchronize all the channel cache */
++	state->get_frontend_internal = 1;
+ 	dib9000_get_frontend(state->fe[0], fep);
++	state->get_frontend_internal = 0;
+ 
+ 	/* retune the other frontends with the found channel */
+ 	channel_status.status = CHANNEL_STATUS_PARAMETERS_SET;
+@@ -2025,6 +2098,28 @@ static int dib9000_set_frontend(struct dvb_frontend *fe, struct dvb_frontend_par
+ 	/* turn off the diversity for the last frontend */
+ 	dib9000_fw_set_diversity_in(state->fe[index_frontend - 1], 0);
+ 
++	DibReleaseLock(&state->demod_lock);
++	if (state->pid_ctrl_index >= 0) {
++		u8 index_pid_filter_cmd;
++		u8 pid_ctrl_index = state->pid_ctrl_index;
++
++		state->pid_ctrl_index = -2;
++		for (index_pid_filter_cmd = 0;
++				index_pid_filter_cmd <= pid_ctrl_index;
++				index_pid_filter_cmd++) {
++			if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER_CTRL)
++				dib9000_fw_pid_filter_ctrl(state->fe[0],
++						state->pid_ctrl[index_pid_filter_cmd].onoff);
++			else if (state->pid_ctrl[index_pid_filter_cmd].cmd == DIB9000_PID_FILTER)
++				dib9000_fw_pid_filter(state->fe[0],
++						state->pid_ctrl[index_pid_filter_cmd].id,
++						state->pid_ctrl[index_pid_filter_cmd].pid,
++						state->pid_ctrl[index_pid_filter_cmd].onoff);
++		}
++	}
++	/* do not postpone any more the pid filtering */
++	state->pid_ctrl_index = -2;
++
+ 	return 0;
+ }
+ 
+@@ -2041,6 +2136,7 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+ 	u8 index_frontend;
+ 	u16 lock = 0, lock_slave = 0;
+ 
++	DibAcquireLock(&state->demod_lock);
+ 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+ 		lock_slave |= dib9000_read_lock(state->fe[index_frontend]);
+ 
+@@ -2059,6 +2155,8 @@ static int dib9000_read_status(struct dvb_frontend *fe, fe_status_t * stat)
+ 	if ((lock & 0x0008) || (lock_slave & 0x0008))
+ 		*stat |= FE_HAS_LOCK;
+ 
++	DibReleaseLock(&state->demod_lock);
++
+ 	return 0;
+ }
+ 
+@@ -2066,10 +2164,14 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
+ {
+ 	struct dib9000_state *state = fe->demodulator_priv;
+ 	u16 *c;
++	int ret = 0;
+ 
++	DibAcquireLock(&state->demod_lock);
+ 	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+-		return -EIO;
++	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
++		ret = -EIO;
++		goto error;
++	}
+ 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR,
+ 			state->i2c_read_buffer, 16 * 2);
+ 	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+@@ -2077,7 +2179,10 @@ static int dib9000_read_ber(struct dvb_frontend *fe, u32 * ber)
+ 	c = (u16 *)state->i2c_read_buffer;
+ 
+ 	*ber = c[10] << 16 | c[11];
+-	return 0;
++
++error:
++	DibReleaseLock(&state->demod_lock);
++	return ret;
+ }
+ 
+ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+@@ -2086,7 +2191,9 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+ 	u8 index_frontend;
+ 	u16 *c = (u16 *)state->i2c_read_buffer;
+ 	u16 val;
++	int ret = 0;
+ 
++	DibAcquireLock(&state->demod_lock);
+ 	*strength = 0;
+ 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++) {
+ 		state->fe[index_frontend]->ops.read_signal_strength(state->fe[index_frontend], &val);
+@@ -2097,8 +2204,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+ 	}
+ 
+ 	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+-		return -EIO;
++	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
++		ret = -EIO;
++		goto error;
++	}
+ 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
+ 	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ 
+@@ -2107,7 +2216,10 @@ static int dib9000_read_signal_strength(struct dvb_frontend *fe, u16 * strength)
+ 		*strength = 65535;
+ 	else
+ 		*strength += val;
+-	return 0;
++
++error:
++	DibReleaseLock(&state->demod_lock);
++	return ret;
+ }
+ 
+ static u32 dib9000_get_snr(struct dvb_frontend *fe)
+@@ -2151,6 +2263,7 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
+ 	u8 index_frontend;
+ 	u32 snr_master;
+ 
++	DibAcquireLock(&state->demod_lock);
+ 	snr_master = dib9000_get_snr(fe);
+ 	for (index_frontend = 1; (index_frontend < MAX_NUMBER_OF_FRONTENDS) && (state->fe[index_frontend] != NULL); index_frontend++)
+ 		snr_master += dib9000_get_snr(state->fe[index_frontend]);
+@@ -2161,6 +2274,8 @@ static int dib9000_read_snr(struct dvb_frontend *fe, u16 * snr)
+ 	} else
+ 		*snr = 0;
+ 
++	DibReleaseLock(&state->demod_lock);
++
+ 	return 0;
+ }
+ 
+@@ -2168,15 +2283,22 @@ static int dib9000_read_unc_blocks(struct dvb_frontend *fe, u32 * unc)
+ {
+ 	struct dib9000_state *state = fe->demodulator_priv;
+ 	u16 *c = (u16 *)state->i2c_read_buffer;
++	int ret = 0;
+ 
++	DibAcquireLock(&state->demod_lock);
+ 	DibAcquireLock(&state->platform.risc.mem_mbx_lock);
+-	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0)
+-		return -EIO;
++	if (dib9000_fw_memmbx_sync(state, FE_SYNC_CHANNEL) < 0) {
++		ret = -EIO;
++		goto error;
++	}
+ 	dib9000_risc_mem_read(state, FE_MM_R_FE_MONITOR, (u8 *) c, 16 * 2);
+ 	DibReleaseLock(&state->platform.risc.mem_mbx_lock);
+ 
+ 	*unc = c[12];
+-	return 0;
++
++error:
++	DibReleaseLock(&state->demod_lock);
++	return ret;
+ }
+ 
+ int dib9000_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 default_addr, u8 first_addr)
+@@ -2322,6 +2444,10 @@ struct dvb_frontend *dib9000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, c
+ 	DibInitLock(&st->platform.risc.mbx_lock);
+ 	DibInitLock(&st->platform.risc.mem_lock);
+ 	DibInitLock(&st->platform.risc.mem_mbx_lock);
++	DibInitLock(&st->demod_lock);
++	st->get_frontend_internal = 0;
++
++	st->pid_ctrl_index = -2;
+ 
+ 	st->fe[0] = fe;
+ 	fe->demodulator_priv = st;
+diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
+index dc5d17a..774d507 100644
+--- a/drivers/media/dvb/frontends/dibx000_common.c
++++ b/drivers/media/dvb/frontends/dibx000_common.c
+@@ -1,4 +1,5 @@
+ #include <linux/i2c.h>
++#include <linux/mutex.h>
+ 
+ #include "dibx000_common.h"
+ 
+@@ -10,6 +11,13 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)");
+ 
+ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
+ {
++	int ret;
++
++	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
++
+ 	mst->i2c_write_buffer[0] = (reg >> 8) & 0xff;
+ 	mst->i2c_write_buffer[1] = reg & 0xff;
+ 	mst->i2c_write_buffer[2] = (val >> 8) & 0xff;
+@@ -21,11 +29,21 @@ static int dibx000_write_word(struct dibx000_i2c_master *mst, u16 reg, u16 val)
+ 	mst->msg[0].buf = mst->i2c_write_buffer;
+ 	mst->msg[0].len = 4;
+ 
+-	return i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
++	ret = i2c_transfer(mst->i2c_adap, mst->msg, 1) != 1 ? -EREMOTEIO : 0;
++	mutex_unlock(&mst->i2c_buffer_lock);
++
++	return ret;
+ }
+ 
+ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
+ {
++	u16 ret;
++
++	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return 0;
++	}
++
+ 	mst->i2c_write_buffer[0] = reg >> 8;
+ 	mst->i2c_write_buffer[1] = reg & 0xff;
+ 
+@@ -42,7 +60,10 @@ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg)
+ 	if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
+ 		dprintk("i2c read error on %d", reg);
+ 
+-	return (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
++	ret = (mst->i2c_read_buffer[0] << 8) | mst->i2c_read_buffer[1];
++	mutex_unlock(&mst->i2c_buffer_lock);
++
++	return ret;
+ }
+ 
+ static int dibx000_is_i2c_done(struct dibx000_i2c_master *mst)
+@@ -257,6 +278,7 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
+ 					struct i2c_msg msg[], int num)
+ {
+ 	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
++	int ret;
+ 
+ 	if (num > 32) {
+ 		dprintk("%s: too much I2C message to be transmitted (%i).\
+@@ -264,10 +286,15 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
+ 		return -ENOMEM;
+ 	}
+ 
+-	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+-
+ 	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7);
+ 
++	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
++
++	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
++
+ 	/* open the gate */
+ 	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+ 	mst->msg[0].addr = mst->i2c_addr;
+@@ -282,7 +309,11 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
+ 	mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+ 	mst->msg[num + 1].len = 4;
+ 
+-	return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
++	ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
++			num : -EIO);
++
++	mutex_unlock(&mst->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ static struct i2c_algorithm dibx000_i2c_gated_gpio67_algo = {
+@@ -294,6 +325,7 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
+ 					struct i2c_msg msg[], int num)
+ {
+ 	struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
++	int ret;
+ 
+ 	if (num > 32) {
+ 		dprintk("%s: too much I2C message to be transmitted (%i).\
+@@ -301,10 +333,14 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
+ 		return -ENOMEM;
+ 	}
+ 
+-	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
+-
+ 	dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER);
+ 
++	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
++	memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
++
+ 	/* open the gate */
+ 	dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
+ 	mst->msg[0].addr = mst->i2c_addr;
+@@ -319,7 +355,10 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
+ 	mst->msg[num + 1].buf = &mst->i2c_write_buffer[4];
+ 	mst->msg[num + 1].len = 4;
+ 
+-	return i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ? num : -EIO;
++	ret = (i2c_transfer(mst->i2c_adap, mst->msg, 2 + num) == 2 + num ?
++			num : -EIO);
++	mutex_unlock(&mst->i2c_buffer_lock);
++	return ret;
+ }
+ 
+ static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
+@@ -390,8 +429,18 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
+ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
+ 				struct i2c_adapter *i2c_adap, u8 i2c_addr)
+ {
+-	u8 tx[4];
+-	struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 };
++	int ret;
++
++	mutex_init(&mst->i2c_buffer_lock);
++	if (mutex_lock_interruptible(&mst->i2c_buffer_lock) < 0) {
++		dprintk("could not acquire lock");
++		return -EINVAL;
++	}
++	memset(mst->msg, 0, sizeof(struct i2c_msg));
++	mst->msg[0].addr = i2c_addr >> 1;
++	mst->msg[0].flags = 0;
++	mst->msg[0].buf = mst->i2c_write_buffer;
++	mst->msg[0].len = 4;
+ 
+ 	mst->device_rev = device_rev;
+ 	mst->i2c_adap = i2c_adap;
+@@ -431,9 +480,12 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
+ 				"DiBX000: could not initialize the master i2c_adapter\n");
+ 
+ 	/* initialize the i2c-master by closing the gate */
+-	dibx000_i2c_gate_ctrl(mst, tx, 0, 0);
++	dibx000_i2c_gate_ctrl(mst, mst->i2c_write_buffer, 0, 0);
++
++	ret = (i2c_transfer(i2c_adap, mst->msg, 1) == 1);
++	mutex_unlock(&mst->i2c_buffer_lock);
+ 
+-	return i2c_transfer(i2c_adap, &m, 1) == 1;
++	return ret;
+ }
+ 
+ EXPORT_SYMBOL(dibx000_init_i2c_master);
+diff --git a/drivers/media/dvb/frontends/dibx000_common.h b/drivers/media/dvb/frontends/dibx000_common.h
+index f031165..5e01147 100644
+--- a/drivers/media/dvb/frontends/dibx000_common.h
++++ b/drivers/media/dvb/frontends/dibx000_common.h
+@@ -33,6 +33,7 @@ struct dibx000_i2c_master {
+ 	struct i2c_msg msg[34];
+ 	u8 i2c_write_buffer[8];
+ 	u8 i2c_read_buffer[2];
++	struct mutex i2c_buffer_lock;
+ };
+ 
+ extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
diff --git a/media-dib0700-correct-error-message.patch b/media-dib0700-correct-error-message.patch
new file mode 100644
index 0000000..5e5d3bf
--- /dev/null
+++ b/media-dib0700-correct-error-message.patch
@@ -0,0 +1,103 @@
+From: Olivier Grenie <olivier.grenie at dibcom.fr>
+Date: Thu, 4 Aug 2011 16:10:03 +0000 (-0300)
+Subject: [media] dib0700: correct error message
+X-Git-Tag: next-20110927~67^2~4^2~223
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fnext%2Flinux-next.git;a=commitdiff_plain;h=680417bb318adc5f1f8f392730776176fbcdedd8
+
+[media] dib0700: correct error message
+
+The goal of this patch is to correct a previous patch. In case of error,
+the err() function should be used instead of dprintk() function.
+
+[mchehab at redhat.com: as I've replaced dprintk by deb_info, on the the
+ previous patch, to avoid breaking bisect, I had to fix a merge conflict
+ on this one]
+Signed-off-by: Olivier Grenie <olivier.grenie at dibcom.fr>
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+
+diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
+index a224e94..b693ed1 100644
+--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
++++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
+@@ -31,7 +31,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
+ 	int ret;
+ 
+ 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+-		deb_info("could not acquire lock");
++		err("could not acquire lock");
+ 		return 0;
+ 	}
+ 
+@@ -117,7 +117,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_
+ 	int ret;
+ 
+ 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+-		deb_info("could not acquire lock");
++		err("could not acquire lock");
+ 		return 0;
+ 	}
+ 
+@@ -138,7 +138,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
+ 
+ 	if (st->fw_version >= 0x10201) {
+ 		if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+-			deb_info("could not acquire lock");
++			err("could not acquire lock");
+ 			return 0;
+ 		}
+ 
+@@ -227,7 +227,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
+ 		} else {
+ 			/* Write request */
+ 			if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+-				deb_info("could not acquire lock");
++				err("could not acquire lock");
+ 				return 0;
+ 			}
+ 			st->buf[0] = REQUEST_NEW_I2C_WRITE;
+@@ -273,7 +273,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
+ 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ 		return -EAGAIN;
+ 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+-		deb_info("could not acquire lock");
++		err("could not acquire lock");
+ 		return 0;
+ 	}
+ 
+@@ -368,7 +368,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
+ 	int ret;
+ 
+ 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+-		deb_info("could not acquire lock");
++		err("could not acquire lock");
+ 		return 0;
+ 	}
+ 
+@@ -400,7 +400,7 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
+ 		return -EINVAL;
+ 
+ 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+-		deb_info("could not acquire lock");
++		err("could not acquire lock");
+ 		return 0;
+ 	}
+ 
+@@ -560,7 +560,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ 	}
+ 
+ 	if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
+-		deb_info("could not acquire lock");
++		err("could not acquire lock");
+ 		return 0;
+ 	}
+ 
+@@ -610,7 +610,7 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
+ 	int new_proto, ret;
+ 
+ 	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
+-		deb_info("could not acquire lock");
++		err("could not acquire lock");
+ 		return 0;
+ 	}
+ 
diff --git a/media-dib0700-protect-the-dib0700-buffer-access.patch b/media-dib0700-protect-the-dib0700-buffer-access.patch
new file mode 100644
index 0000000..109cab8
--- /dev/null
+++ b/media-dib0700-protect-the-dib0700-buffer-access.patch
@@ -0,0 +1,248 @@
+From: Olivier Grenie <olivier.grenie at dibcom.fr>
+Date: Mon, 1 Aug 2011 15:45:58 +0000 (-0300)
+Subject: [media] dib0700: protect the dib0700 buffer access
+X-Git-Tag: next-20110927~67^2~4^2~224
+X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Fnext%2Flinux-next.git;a=commitdiff_plain;h=bff469f4167fdabfe15294f375577d7eadbaa1bb
+
+[media] dib0700: protect the dib0700 buffer access
+
+This patch protects the common buffer access inside the dib0700 in order
+to manage concurrent access. This protection is done using mutex.
+
+Cc: Mauro Carvalho Chehab <mchehab at redhat.com>
+Cc: Florian Mickler <florian at mickler.org>
+Cc: stable at kernel.org
+Signed-off-by: Javier Marcet <javier at marcet.info>
+Signed-off-by: Olivier Grenie <olivier.grenie at dibcom.fr>
+Signed-off-by: Patrick Boettcher <patrick.boettcher at dibcom.fr>
+[mchehab at redhat.com: dprint requires 3 arguments. Replaced by dib_info]
+Signed-off-by: Mauro Carvalho Chehab <mchehab at redhat.com>
+---
+
+diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
+index 5eb91b4..a224e94 100644
+--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
++++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
+@@ -30,6 +30,11 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
+ 	struct dib0700_state *st = d->priv;
+ 	int ret;
+ 
++	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++		deb_info("could not acquire lock");
++		return 0;
++	}
++
+ 	ret = usb_control_msg(d->udev, usb_rcvctrlpipe(d->udev, 0),
+ 				  REQUEST_GET_VERSION,
+ 				  USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
+@@ -46,6 +51,7 @@ int dib0700_get_version(struct dvb_usb_device *d, u32 *hwversion,
+ 	if (fwtype != NULL)
+ 		*fwtype     = (st->buf[12] << 24) | (st->buf[13] << 16) |
+ 			(st->buf[14] << 8) | st->buf[15];
++	mutex_unlock(&d->usb_mutex);
+ 	return ret;
+ }
+ 
+@@ -108,7 +114,12 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen
+ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
+ {
+ 	struct dib0700_state *st = d->priv;
+-	s16 ret;
++	int ret;
++
++	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++		deb_info("could not acquire lock");
++		return 0;
++	}
+ 
+ 	st->buf[0] = REQUEST_SET_GPIO;
+ 	st->buf[1] = gpio;
+@@ -116,6 +127,7 @@ int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_
+ 
+ 	ret = dib0700_ctrl_wr(d, st->buf, 3);
+ 
++	mutex_unlock(&d->usb_mutex);
+ 	return ret;
+ }
+ 
+@@ -125,6 +137,11 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
+ 	int ret;
+ 
+ 	if (st->fw_version >= 0x10201) {
++		if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++			deb_info("could not acquire lock");
++			return 0;
++		}
++
+ 		st->buf[0] = REQUEST_SET_USB_XFER_LEN;
+ 		st->buf[1] = (nb_ts_packets >> 8) & 0xff;
+ 		st->buf[2] = nb_ts_packets & 0xff;
+@@ -132,6 +149,7 @@ static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
+ 		deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+ 
+ 		ret = dib0700_ctrl_wr(d, st->buf, 3);
++		mutex_unlock(&d->usb_mutex);
+ 	} else {
+ 		deb_info("this firmware does not allow to change the USB xfer len\n");
+ 		ret = -EIO;
+@@ -208,6 +226,10 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
+ 
+ 		} else {
+ 			/* Write request */
++			if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++				deb_info("could not acquire lock");
++				return 0;
++			}
+ 			st->buf[0] = REQUEST_NEW_I2C_WRITE;
+ 			st->buf[1] = msg[i].addr << 1;
+ 			st->buf[2] = (en_start << 7) | (en_stop << 6) |
+@@ -227,6 +249,7 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
+ 						 USB_TYPE_VENDOR | USB_DIR_OUT,
+ 						 0, 0, st->buf, msg[i].len + 4,
+ 						 USB_CTRL_GET_TIMEOUT);
++			mutex_unlock(&d->usb_mutex);
+ 			if (result < 0) {
+ 				deb_info("i2c write error (status = %d)\n", result);
+ 				break;
+@@ -249,6 +272,10 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
+ 
+ 	if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ 		return -EAGAIN;
++	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++		deb_info("could not acquire lock");
++		return 0;
++	}
+ 
+ 	for (i = 0; i < num; i++) {
+ 		/* fill in the address */
+@@ -279,6 +306,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
+ 				break;
+ 		}
+ 	}
++	mutex_unlock(&d->usb_mutex);
+ 	mutex_unlock(&d->i2c_mutex);
+ 
+ 	return i;
+@@ -337,7 +365,12 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
+ 	u16 pll_loopdiv, u16 free_div, u16 dsuScaler)
+ {
+ 	struct dib0700_state *st = d->priv;
+-	s16 ret;
++	int ret;
++
++	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++		deb_info("could not acquire lock");
++		return 0;
++	}
+ 
+ 	st->buf[0] = REQUEST_SET_CLOCK;
+ 	st->buf[1] = (en_pll << 7) | (pll_src << 6) |
+@@ -352,6 +385,7 @@ static int dib0700_set_clock(struct dvb_usb_device *d, u8 en_pll,
+ 	st->buf[9] =  dsuScaler         & 0xff; /* LSB */
+ 
+ 	ret = dib0700_ctrl_wr(d, st->buf, 10);
++	mutex_unlock(&d->usb_mutex);
+ 
+ 	return ret;
+ }
+@@ -360,10 +394,16 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
+ {
+ 	struct dib0700_state *st = d->priv;
+ 	u16 divider;
++	int ret;
+ 
+ 	if (scl_kHz == 0)
+ 		return -EINVAL;
+ 
++	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++		deb_info("could not acquire lock");
++		return 0;
++	}
++
+ 	st->buf[0] = REQUEST_SET_I2C_PARAM;
+ 	divider = (u16) (30000 / scl_kHz);
+ 	st->buf[1] = 0;
+@@ -379,7 +419,11 @@ int dib0700_set_i2c_speed(struct dvb_usb_device *d, u16 scl_kHz)
+ 	deb_info("setting I2C speed: %04x %04x %04x (%d kHz).",
+ 		(st->buf[2] << 8) | (st->buf[3]), (st->buf[4] << 8) |
+ 		st->buf[5], (st->buf[6] << 8) | st->buf[7], scl_kHz);
+-	return dib0700_ctrl_wr(d, st->buf, 8);
++
++	ret = dib0700_ctrl_wr(d, st->buf, 8);
++	mutex_unlock(&d->usb_mutex);
++
++	return ret;
+ }
+ 
+ 
+@@ -515,6 +559,11 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ 		}
+ 	}
+ 
++	if (mutex_lock_interruptible(&adap->dev->usb_mutex) < 0) {
++		deb_info("could not acquire lock");
++		return 0;
++	}
++
+ 	st->buf[0] = REQUEST_ENABLE_VIDEO;
+ 	/* this bit gives a kind of command,
+ 	 * rather than enabling something or not */
+@@ -548,7 +597,10 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+ 
+ 	deb_info("data for streaming: %x %x\n", st->buf[1], st->buf[2]);
+ 
+-	return dib0700_ctrl_wr(adap->dev, st->buf, 4);
++	ret = dib0700_ctrl_wr(adap->dev, st->buf, 4);
++	mutex_unlock(&adap->dev->usb_mutex);
++
++	return ret;
+ }
+ 
+ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
+@@ -557,6 +609,11 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
+ 	struct dib0700_state *st = d->priv;
+ 	int new_proto, ret;
+ 
++	if (mutex_lock_interruptible(&d->usb_mutex) < 0) {
++		deb_info("could not acquire lock");
++		return 0;
++	}
++
+ 	st->buf[0] = REQUEST_SET_RC;
+ 	st->buf[1] = 0;
+ 	st->buf[2] = 0;
+@@ -567,23 +624,29 @@ int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
+ 	else if (rc_type == RC_TYPE_NEC)
+ 		new_proto = 0;
+ 	else if (rc_type == RC_TYPE_RC6) {
+-		if (st->fw_version < 0x10200)
+-			return -EINVAL;
++		if (st->fw_version < 0x10200) {
++			ret = -EINVAL;
++			goto out;
++		}
+ 
+ 		new_proto = 2;
+-	} else
+-		return -EINVAL;
++	} else {
++		ret = -EINVAL;
++		goto out;
++	}
+ 
+ 	st->buf[1] = new_proto;
+ 
+ 	ret = dib0700_ctrl_wr(d, st->buf, 3);
+ 	if (ret < 0) {
+ 		err("ir protocol setup failed");
+-		return ret;
++		goto out;
+ 	}
+ 
+ 	d->props.rc.core.protocol = rc_type;
+ 
++out:
++	mutex_unlock(&d->usb_mutex);
+ 	return ret;
+ }
+ 


More information about the scm-commits mailing list