diff options
author | Patrick Boettcher <Patrick.Boettcher@dibcom.fr> | 2011-08-03 17:08:21 +0200 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2011-08-06 14:25:15 +0200 |
commit | 79fcce3230b140f7675f8529ee53fe2f9644f902 (patch) | |
tree | 548f87873e553e0c0e69e13f78c360e0d351f857 /drivers/media/dvb/frontends/dib0090.c | |
parent | v4l2-ioctl: properly return -EINVAL when parameters are wrong (diff) | |
download | linux-79fcce3230b140f7675f8529ee53fe2f9644f902.tar.xz linux-79fcce3230b140f7675f8529ee53fe2f9644f902.zip |
[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@redhat.com>
Cc: Florian Mickler <florian@mickler.org>
Cc: stable@kernel.org
Signed-off-by: Olivier Grenie <olivier.grenie@dibcom.fr>
Signed-off-by: Patrick Boettcher <Patrick.Boettcher@dibcom.fr>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'drivers/media/dvb/frontends/dib0090.c')
-rw-r--r-- | drivers/media/dvb/frontends/dib0090.c | 70 |
1 files changed, 58 insertions, 12 deletions
diff --git a/drivers/media/dvb/frontends/dib0090.c b/drivers/media/dvb/frontends/dib0090.c index c9c935ae41e4..b174d1c78583 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) |