Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 79fcce32 authored by Patrick Boettcher's avatar Patrick Boettcher Committed by Mauro Carvalho Chehab
Browse files

[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: default avatarOlivier Grenie <olivier.grenie@dibcom.fr>
Signed-off-by: default avatarPatrick Boettcher <Patrick.Boettcher@dibcom.fr>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent a5f2db53
Loading
Loading
Loading
Loading
+30 −7
Original line number Diff line number Diff line
@@ -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)
+58 −12
Original line number Diff line number Diff line
@@ -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)
+25 −2
Original line number Diff line number Diff line
@@ -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;

+28 −4
Original line number Diff line number Diff line
@@ -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 */

@@ -2335,6 +2358,7 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
	/* FIXME: make sure the dev.parent field is initialized, or else
	   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
+61 −11
Original line number Diff line number Diff line
@@ -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;

Loading