Skip to content

Commit

Permalink
[media] DiBcom: protect the I2C bufer access
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Patrick Boettcher authored and Mauro Carvalho Chehab committed Aug 6, 2011
1 parent a5f2db5 commit 79fcce3
Show file tree
Hide file tree
Showing 8 changed files with 412 additions and 67 deletions.
37 changes: 30 additions & 7 deletions drivers/media/dvb/frontends/dib0070.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>

#include "dvb_frontend.h"

Expand Down Expand Up @@ -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));
Expand All @@ -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;
Expand All @@ -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 { \
Expand Down Expand Up @@ -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)
Expand Down
70 changes: 58 additions & 12 deletions drivers/media/dvb/frontends/dib0090.c
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>

#include "dvb_frontend.h"

Expand Down Expand Up @@ -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 {
Expand All @@ -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));
Expand All @@ -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;
Expand All @@ -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));
Expand All @@ -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;

Expand All @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down
27 changes: 25 additions & 2 deletions drivers/media/dvb/frontends/dib7000m.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/i2c.h>
#include <linux/mutex.h>

#include "dvb_frontend.h"

Expand Down Expand Up @@ -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 {
Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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)
{
Expand Down Expand Up @@ -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;

Expand Down
32 changes: 28 additions & 4 deletions drivers/media/dvb/frontends/dib7000p.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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 {
Expand All @@ -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;

Expand All @@ -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;
Expand All @@ -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)
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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 */

Expand All @@ -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
Expand Down
Loading

0 comments on commit 79fcce3

Please sign in to comment.