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

[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
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h>
#include "dvb_frontend.h" #include "dvb_frontend.h"
...@@ -78,10 +79,18 @@ struct dib0070_state { ...@@ -78,10 +79,18 @@ struct dib0070_state {
struct i2c_msg msg[2]; struct i2c_msg msg[2];
u8 i2c_write_buffer[3]; u8 i2c_write_buffer[3];
u8 i2c_read_buffer[2]; 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; state->i2c_write_buffer[0] = reg;
memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); 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) ...@@ -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) { if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
printk(KERN_WARNING "DiB0070 I2C read failed\n"); printk(KERN_WARNING "DiB0070 I2C read failed\n");
return 0; ret = 0;
} } else
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 dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) 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[0] = reg;
state->i2c_write_buffer[1] = val >> 8; state->i2c_write_buffer[1] = val >> 8;
state->i2c_write_buffer[2] = val & 0xff; state->i2c_write_buffer[2] = val & 0xff;
...@@ -115,9 +134,12 @@ static int dib0070_write_reg(struct dib0070_state *state, u8 reg, u16 val) ...@@ -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) { if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0070 I2C write failed\n"); printk(KERN_WARNING "DiB0070 I2C write failed\n");
return -EREMOTEIO; ret = -EREMOTEIO;
} } else
return 0; ret = 0;
mutex_unlock(&state->i2c_buffer_lock);
return ret;
} }
#define HARD_RESET(state) do { \ #define HARD_RESET(state) do { \
...@@ -734,6 +756,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter ...@@ -734,6 +756,7 @@ struct dvb_frontend *dib0070_attach(struct dvb_frontend *fe, struct i2c_adapter
state->cfg = cfg; state->cfg = cfg;
state->i2c = i2c; state->i2c = i2c;
state->fe = fe; state->fe = fe;
mutex_init(&state->i2c_buffer_lock);
fe->tuner_priv = state; fe->tuner_priv = state;
if (dib0070_reset(fe) != 0) if (dib0070_reset(fe) != 0)
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h>
#include "dvb_frontend.h" #include "dvb_frontend.h"
...@@ -196,6 +197,7 @@ struct dib0090_state { ...@@ -196,6 +197,7 @@ struct dib0090_state {
struct i2c_msg msg[2]; struct i2c_msg msg[2];
u8 i2c_write_buffer[3]; u8 i2c_write_buffer[3];
u8 i2c_read_buffer[2]; u8 i2c_read_buffer[2];
struct mutex i2c_buffer_lock;
}; };
struct dib0090_fw_state { struct dib0090_fw_state {
...@@ -208,10 +210,18 @@ struct dib0090_fw_state { ...@@ -208,10 +210,18 @@ struct dib0090_fw_state {
struct i2c_msg msg; struct i2c_msg msg;
u8 i2c_write_buffer[2]; u8 i2c_write_buffer[2];
u8 i2c_read_buffer[2]; u8 i2c_read_buffer[2];
struct mutex i2c_buffer_lock;
}; };
static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) 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; state->i2c_write_buffer[0] = reg;
memset(state->msg, 0, 2 * sizeof(struct i2c_msg)); memset(state->msg, 0, 2 * sizeof(struct i2c_msg));
...@@ -226,14 +236,24 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg) ...@@ -226,14 +236,24 @@ static u16 dib0090_read_reg(struct dib0090_state *state, u8 reg)
if (i2c_transfer(state->i2c, state->msg, 2) != 2) { if (i2c_transfer(state->i2c, state->msg, 2) != 2) {
printk(KERN_WARNING "DiB0090 I2C read failed\n"); 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) 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[0] = reg & 0xff;
state->i2c_write_buffer[1] = val >> 8; state->i2c_write_buffer[1] = val >> 8;
state->i2c_write_buffer[2] = val & 0xff; state->i2c_write_buffer[2] = val & 0xff;
...@@ -246,13 +266,23 @@ static int dib0090_write_reg(struct dib0090_state *state, u32 reg, u16 val) ...@@ -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) { if (i2c_transfer(state->i2c, state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0090 I2C write failed\n"); printk(KERN_WARNING "DiB0090 I2C write failed\n");
return -EREMOTEIO; ret = -EREMOTEIO;
} } else
return 0; ret = 0;
mutex_unlock(&state->i2c_buffer_lock);
return ret;
} }
static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg) 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; state->i2c_write_buffer[0] = reg;
memset(&state->msg, 0, sizeof(struct i2c_msg)); 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) ...@@ -262,13 +292,24 @@ static u16 dib0090_fw_read_reg(struct dib0090_fw_state *state, u8 reg)
state->msg.len = 2; state->msg.len = 2;
if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0090 I2C read failed\n"); printk(KERN_WARNING "DiB0090 I2C read failed\n");
return 0; ret = 0;
} } else
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 dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val) 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[0] = val >> 8;
state->i2c_write_buffer[1] = val & 0xff; 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) ...@@ -279,9 +320,12 @@ static int dib0090_fw_write_reg(struct dib0090_fw_state *state, u8 reg, u16 val)
state->msg.len = 2; state->msg.len = 2;
if (i2c_transfer(state->i2c, &state->msg, 1) != 1) { if (i2c_transfer(state->i2c, &state->msg, 1) != 1) {
printk(KERN_WARNING "DiB0090 I2C write failed\n"); printk(KERN_WARNING "DiB0090 I2C write failed\n");
return -EREMOTEIO; ret = -EREMOTEIO;
} } else
return 0; 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) #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 ...@@ -2440,6 +2484,7 @@ struct dvb_frontend *dib0090_register(struct dvb_frontend *fe, struct i2c_adapte
st->config = config; st->config = config;
st->i2c = i2c; st->i2c = i2c;
st->fe = fe; st->fe = fe;
mutex_init(&st->i2c_buffer_lock);
fe->tuner_priv = st; fe->tuner_priv = st;
if (config->wbd == NULL) if (config->wbd == NULL)
...@@ -2471,6 +2516,7 @@ struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_ada ...@@ -2471,6 +2516,7 @@ struct dvb_frontend *dib0090_fw_register(struct dvb_frontend *fe, struct i2c_ada
st->config = config; st->config = config;
st->i2c = i2c; st->i2c = i2c;
st->fe = fe; st->fe = fe;
mutex_init(&st->i2c_buffer_lock);
fe->tuner_priv = st; fe->tuner_priv = st;
if (dib0090_fw_reset_digital(fe, st->config) != 0) if (dib0090_fw_reset_digital(fe, st->config) != 0)
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h>
#include "dvb_frontend.h" #include "dvb_frontend.h"
...@@ -55,6 +56,7 @@ struct dib7000m_state { ...@@ -55,6 +56,7 @@ struct dib7000m_state {
struct i2c_msg msg[2]; struct i2c_msg msg[2];
u8 i2c_write_buffer[4]; u8 i2c_write_buffer[4];
u8 i2c_read_buffer[2]; u8 i2c_read_buffer[2];
struct mutex i2c_buffer_lock;
}; };
enum dib7000m_power_mode { enum dib7000m_power_mode {
...@@ -69,6 +71,13 @@ enum dib7000m_power_mode { ...@@ -69,6 +71,13 @@ enum dib7000m_power_mode {
static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) 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[0] = (reg >> 8) | 0x80;
state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[1] = reg & 0xff;
...@@ -85,11 +94,21 @@ static u16 dib7000m_read_word(struct dib7000m_state *state, u16 reg) ...@@ -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) if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
dprintk("i2c read error on %d",reg); 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) 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[0] = (reg >> 8) & 0xff;
state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[1] = reg & 0xff;
state->i2c_write_buffer[2] = (val >> 8) & 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) ...@@ -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].buf = state->i2c_write_buffer;
state->msg[0].len = 4; 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) 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, ...@@ -1385,6 +1407,7 @@ struct dvb_frontend * dib7000m_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
demod = &st->demod; demod = &st->demod;
demod->demodulator_priv = st; demod->demodulator_priv = st;
memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops)); memcpy(&st->demod.ops, &dib7000m_ops, sizeof(struct dvb_frontend_ops));
mutex_init(&st->i2c_buffer_lock);
st->timf_default = cfg->bw->timf; st->timf_default = cfg->bw->timf;
......
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h>
#include "dvb_math.h" #include "dvb_math.h"
#include "dvb_frontend.h" #include "dvb_frontend.h"
...@@ -68,6 +69,7 @@ struct dib7000p_state { ...@@ -68,6 +69,7 @@ struct dib7000p_state {
struct i2c_msg msg[2]; struct i2c_msg msg[2];
u8 i2c_write_buffer[4]; u8 i2c_write_buffer[4];
u8 i2c_read_buffer[2]; u8 i2c_read_buffer[2];
struct mutex i2c_buffer_lock;
}; };
enum dib7000p_power_mode { enum dib7000p_power_mode {
...@@ -81,6 +83,13 @@ static int dib7090_set_diversity_in(struct dvb_frontend *fe, int onoff); ...@@ -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) 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[0] = reg >> 8;
state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[1] = reg & 0xff;
...@@ -97,11 +106,20 @@ static u16 dib7000p_read_word(struct dib7000p_state *state, u16 reg) ...@@ -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) if (i2c_transfer(state->i2c_adap, state->msg, 2) != 2)
dprintk("i2c read error on %d", reg); 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) 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[0] = (reg >> 8) & 0xff;
state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[1] = reg & 0xff;
state->i2c_write_buffer[2] = (val >> 8) & 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) ...@@ -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].buf = state->i2c_write_buffer;
state->msg[0].len = 4; 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) 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 ...@@ -1646,6 +1667,7 @@ int dib7000p_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defau
return -ENOMEM; return -ENOMEM;
dpst->i2c_adap = i2c; dpst->i2c_adap = i2c;
mutex_init(&dpst->i2c_buffer_lock);
for (k = no_of_demods - 1; k >= 0; k--) { for (k = no_of_demods - 1; k >= 0; k--) {
dpst->cfg = cfg[k]; dpst->cfg = cfg[k];
...@@ -2324,6 +2346,7 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, ...@@ -2324,6 +2346,7 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
demod = &st->demod; demod = &st->demod;
demod->demodulator_priv = st; demod->demodulator_priv = st;
memcpy(&st->demod.ops, &dib7000p_ops, sizeof(struct dvb_frontend_ops)); 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 */ 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, ...@@ -2333,8 +2356,9 @@ struct dvb_frontend *dib7000p_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr,
st->version = dib7000p_read_word(st, 897); st->version = dib7000p_read_word(st, 897);
/* FIXME: make sure the dev.parent field is initialized, or else /* FIXME: make sure the dev.parent field is initialized, or else
request_firmware() will hit an OOPS (this should be moved somewhere request_firmware() will hit an OOPS (this should be moved somewhere
more common) */ 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 /* FIXME: make sure the dev.parent field is initialized, or else
request_firmware() will hit an OOPS (this should be moved somewhere request_firmware() will hit an OOPS (this should be moved somewhere
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h>
#include "dvb_math.h" #include "dvb_math.h"
#include "dvb_frontend.h" #include "dvb_frontend.h"
...@@ -37,6 +39,7 @@ struct i2c_device { ...@@ -37,6 +39,7 @@ struct i2c_device {
u8 addr; u8 addr;
u8 *i2c_write_buffer; u8 *i2c_write_buffer;
u8 *i2c_read_buffer; u8 *i2c_read_buffer;
struct mutex *i2c_buffer_lock;
}; };
struct dib8000_state { struct dib8000_state {
...@@ -77,6 +80,7 @@ struct dib8000_state { ...@@ -77,6 +80,7 @@ struct dib8000_state {
struct i2c_msg msg[2]; struct i2c_msg msg[2];
u8 i2c_write_buffer[4]; u8 i2c_write_buffer[4];
u8 i2c_read_buffer[2]; u8 i2c_read_buffer[2];
struct mutex i2c_buffer_lock;
}; };
enum dib8000_power_mode { enum dib8000_power_mode {
...@@ -86,24 +90,39 @@ enum dib8000_power_mode { ...@@ -86,24 +90,39 @@ enum dib8000_power_mode {
static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg)
{ {
u16 ret;
struct i2c_msg msg[2] = { struct i2c_msg msg[2] = {
{.addr = i2c->addr >> 1, .flags = 0, {.addr = i2c->addr >> 1, .flags = 0, .len = 2},
.buf = i2c->i2c_write_buffer, .len = 2}, {.addr = i2c->addr >> 1, .flags = I2C_M_RD, .len = 2},
{.addr = i2c->addr >> 1, .flags = I2C_M_RD,
.buf = i2c->i2c_read_buffer, .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[0] = reg >> 8;
msg[0].buf[1] = reg & 0xff; msg[0].buf[1] = reg & 0xff;
msg[1].buf = i2c->i2c_read_buffer;
if (i2c_transfer(i2c->adap, msg, 2) != 2) if (i2c_transfer(i2c->adap, msg, 2) != 2)
dprintk("i2c read error on %d", reg); 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) 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[0] = reg >> 8;
state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[1] = reg & 0xff;
...@@ -120,7 +139,10 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) ...@@ -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) if (i2c_transfer(state->i2c.adap, state->msg, 2) != 2)
dprintk("i2c read error on %d", reg); 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) static u32 dib8000_read32(struct dib8000_state *state, u16 reg)
...@@ -135,22 +157,35 @@ 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) static int dib8000_i2c_write16(struct i2c_device *i2c, u16 reg, u16 val)
{ {
struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, struct i2c_msg msg = {.addr = i2c->addr >> 1, .flags = 0, .len = 4};
.buf = i2c->i2c_write_buffer, .len = 4};
int ret = 0; 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[0] = (reg >> 8) & 0xff;
msg.buf[1] = reg & 0xff; msg.buf[1] = reg & 0xff;
msg.buf[2] = (val >> 8) & 0xff; msg.buf[2] = (val >> 8) & 0xff;
msg.buf[3] = val & 0xff; msg.buf[3] = val & 0xff;
ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0; ret = i2c_transfer(i2c->adap, &msg, 1) != 1 ? -EREMOTEIO : 0;
mutex_unlock(i2c->i2c_buffer_lock);
return ret; return ret;
} }
static int dib8000_write_word(struct dib8000_state *state, u16 reg, u16 val) 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[0] = (reg >> 8) & 0xff;
state->i2c_write_buffer[1] = reg & 0xff; state->i2c_write_buffer[1] = reg & 0xff;
state->i2c_write_buffer[2] = (val >> 8) & 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) ...@@ -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].buf = state->i2c_write_buffer;
state->msg[0].len = 4; 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] = { 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 ...@@ -2434,8 +2473,15 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
if (!client.i2c_read_buffer) { if (!client.i2c_read_buffer) {
dprintk("%s: not enough memory", __func__); dprintk("%s: not enough memory", __func__);
ret = -ENOMEM; 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--) { for (k = no_of_demods - 1; k >= 0; k--) {
/* designated i2c address */ /* designated i2c address */
...@@ -2476,8 +2522,10 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau ...@@ -2476,8 +2522,10 @@ int dib8000_i2c_enumeration(struct i2c_adapter *host, int no_of_demods, u8 defau
} }
error: error:
kfree(client.i2c_buffer_lock);
error_memory_lock:
kfree(client.i2c_read_buffer); kfree(client.i2c_read_buffer);
error_memory: error_memory_read:
kfree(client.i2c_write_buffer); kfree(client.i2c_write_buffer);
return ret; return ret;
...@@ -2581,6 +2629,8 @@ struct dvb_frontend *dib8000_attach(struct i2c_adapter *i2c_adap, u8 i2c_addr, s ...@@ -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.addr = i2c_addr;
state->i2c.i2c_write_buffer = state->i2c_write_buffer; state->i2c.i2c_write_buffer = state->i2c_write_buffer;
state->i2c.i2c_read_buffer = state->i2c_read_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_val = cfg->gpio_val;
state->gpio_dir = cfg->gpio_dir; state->gpio_dir = cfg->gpio_dir;
......
This diff is collapsed.
#include <linux/i2c.h> #include <linux/i2c.h>
#include <linux/mutex.h>
#include "dibx000_common.h" #include "dibx000_common.h"
...@@ -10,6 +11,13 @@ MODULE_PARM_DESC(debug, "turn on debugging (default: 0)"); ...@@ -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) 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[0] = (reg >> 8) & 0xff;
mst->i2c_write_buffer[1] = reg & 0xff; mst->i2c_write_buffer[1] = reg & 0xff;
mst->i2c_write_buffer[2] = (val >> 8) & 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) ...@@ -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].buf = mst->i2c_write_buffer;
mst->msg[0].len = 4; 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) 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[0] = reg >> 8;
mst->i2c_write_buffer[1] = reg & 0xff; mst->i2c_write_buffer[1] = reg & 0xff;
...@@ -42,7 +60,10 @@ static u16 dibx000_read_word(struct dibx000_i2c_master *mst, u16 reg) ...@@ -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) if (i2c_transfer(mst->i2c_adap, mst->msg, 2) != 2)
dprintk("i2c read error on %d", reg); 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) 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, ...@@ -257,6 +278,7 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msg[], int num) struct i2c_msg msg[], int num)
{ {
struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
int ret;
if (num > 32) { if (num > 32) {
dprintk("%s: too much I2C message to be transmitted (%i).\ 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, ...@@ -264,10 +286,15 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap,
return -ENOMEM; return -ENOMEM;
} }
memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_GPIO_6_7); 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 */ /* open the gate */
dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
mst->msg[0].addr = mst->i2c_addr; mst->msg[0].addr = mst->i2c_addr;
...@@ -282,7 +309,11 @@ static int dibx000_i2c_gated_gpio67_xfer(struct i2c_adapter *i2c_adap, ...@@ -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].buf = &mst->i2c_write_buffer[4];
mst->msg[num + 1].len = 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 = { 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, ...@@ -294,6 +325,7 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
struct i2c_msg msg[], int num) struct i2c_msg msg[], int num)
{ {
struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap); struct dibx000_i2c_master *mst = i2c_get_adapdata(i2c_adap);
int ret;
if (num > 32) { if (num > 32) {
dprintk("%s: too much I2C message to be transmitted (%i).\ 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, ...@@ -301,10 +333,14 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap,
return -ENOMEM; return -ENOMEM;
} }
memset(mst->msg, 0, sizeof(struct i2c_msg) * (2 + num));
dibx000_i2c_select_interface(mst, DIBX000_I2C_INTERFACE_TUNER); 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 */ /* open the gate */
dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1); dibx000_i2c_gate_ctrl(mst, &mst->i2c_write_buffer[0], msg[0].addr, 1);
mst->msg[0].addr = mst->i2c_addr; mst->msg[0].addr = mst->i2c_addr;
...@@ -319,7 +355,10 @@ static int dibx000_i2c_gated_tuner_xfer(struct i2c_adapter *i2c_adap, ...@@ -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].buf = &mst->i2c_write_buffer[4];
mst->msg[num + 1].len = 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 = { static struct i2c_algorithm dibx000_i2c_gated_tuner_algo = {
...@@ -390,8 +429,18 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap, ...@@ -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, int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev,
struct i2c_adapter *i2c_adap, u8 i2c_addr) struct i2c_adapter *i2c_adap, u8 i2c_addr)
{ {
u8 tx[4]; int ret;
struct i2c_msg m = {.addr = i2c_addr >> 1,.buf = tx,.len = 4 };
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->device_rev = device_rev;
mst->i2c_adap = i2c_adap; mst->i2c_adap = i2c_adap;
...@@ -431,9 +480,12 @@ int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, u16 device_rev, ...@@ -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"); "DiBX000: could not initialize the master i2c_adapter\n");
/* initialize the i2c-master by closing the gate */ /* 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); EXPORT_SYMBOL(dibx000_init_i2c_master);
......
...@@ -33,6 +33,7 @@ struct dibx000_i2c_master { ...@@ -33,6 +33,7 @@ struct dibx000_i2c_master {
struct i2c_msg msg[34]; struct i2c_msg msg[34];
u8 i2c_write_buffer[8]; u8 i2c_write_buffer[8];
u8 i2c_read_buffer[2]; u8 i2c_read_buffer[2];
struct mutex i2c_buffer_lock;
}; };
extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst, extern int dibx000_init_i2c_master(struct dibx000_i2c_master *mst,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment