diff options
Diffstat (limited to 'drivers/media/dvb-frontends')
23 files changed, 369 insertions, 82 deletions
diff --git a/drivers/media/dvb-frontends/af9013.c b/drivers/media/dvb-frontends/af9013.c index a204f2828820..fb504f1e9125 100644 --- a/drivers/media/dvb-frontends/af9013.c +++ b/drivers/media/dvb-frontends/af9013.c @@ -24,6 +24,9 @@ #include "af9013_priv.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + struct af9013_state { struct i2c_adapter *i2c; struct dvb_frontend fe; @@ -50,16 +53,23 @@ static int af9013_wr_regs_i2c(struct af9013_state *priv, u8 mbox, u16 reg, const u8 *val, int len) { int ret; - u8 buf[3+len]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { .addr = priv->config.i2c_addr, .flags = 0, - .len = sizeof(buf), + .len = 3 + len, .buf = buf, } }; + if (3 + len > sizeof(buf)) { + dev_warn(&priv->i2c->dev, + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, len); + return -EINVAL; + } + buf[0] = (reg >> 8) & 0xff; buf[1] = (reg >> 0) & 0xff; buf[2] = mbox; diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index a777b4b944eb..65728c25ea05 100644 --- a/drivers/media/dvb-frontends/af9033.c +++ b/drivers/media/dvb-frontends/af9033.c @@ -21,6 +21,9 @@ #include "af9033_priv.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + struct af9033_state { struct i2c_adapter *i2c; struct dvb_frontend fe; @@ -40,16 +43,23 @@ static int af9033_wr_regs(struct af9033_state *state, u32 reg, const u8 *val, int len) { int ret; - u8 buf[3 + len]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { .addr = state->cfg.i2c_addr, .flags = 0, - .len = sizeof(buf), + .len = 3 + len, .buf = buf, } }; + if (3 + len > sizeof(buf)) { + dev_warn(&state->i2c->dev, + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, len); + return -EINVAL; + } + buf[0] = (reg >> 16) & 0xff; buf[1] = (reg >> 8) & 0xff; buf[2] = (reg >> 0) & 0xff; @@ -160,11 +170,18 @@ static int af9033_rd_reg_mask(struct af9033_state *state, u32 reg, u8 *val, static int af9033_wr_reg_val_tab(struct af9033_state *state, const struct reg_val *tab, int tab_len) { +#define MAX_TAB_LEN 212 int ret, i, j; - u8 buf[tab_len]; + u8 buf[1 + MAX_TAB_LEN]; dev_dbg(&state->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len); + if (tab_len > sizeof(buf)) { + dev_warn(&state->i2c->dev, "%s: tab len %d is too big\n", + KBUILD_MODNAME, tab_len); + return -EINVAL; + } + for (i = 0, j = 0; i < tab_len; i++) { buf[j] = tab[i].val; diff --git a/drivers/media/dvb-frontends/bcm3510.c b/drivers/media/dvb-frontends/bcm3510.c index 1b77909c0c71..39a29dd29519 100644 --- a/drivers/media/dvb-frontends/bcm3510.c +++ b/drivers/media/dvb-frontends/bcm3510.c @@ -44,6 +44,9 @@ #include "bcm3510.h" #include "bcm3510_priv.h" +/* Max transfer size done by bcm3510_do_hab_cmd() function */ +#define MAX_XFER_SIZE 128 + struct bcm3510_state { struct i2c_adapter* i2c; @@ -201,9 +204,19 @@ static int bcm3510_hab_send_request(struct bcm3510_state *st, u8 *buf, int len) static int bcm3510_do_hab_cmd(struct bcm3510_state *st, u8 cmd, u8 msgid, u8 *obuf, u8 olen, u8 *ibuf, u8 ilen) { - u8 ob[olen+2],ib[ilen+2]; + u8 ob[MAX_XFER_SIZE], ib[MAX_XFER_SIZE]; int ret = 0; + if (ilen + 2 > sizeof(ib)) { + deb_hab("do_hab_cmd: ilen=%d is too big!\n", ilen); + return -EINVAL; + } + + if (olen + 2 > sizeof(ob)) { + deb_hab("do_hab_cmd: olen=%d is too big!\n", olen); + return -EINVAL; + } + ob[0] = cmd; ob[1] = msgid; memcpy(&ob[2],obuf,olen); diff --git a/drivers/media/dvb-frontends/cxd2820r_core.c b/drivers/media/dvb-frontends/cxd2820r_core.c index 7ca5c69dd200..03930d5e9fea 100644 --- a/drivers/media/dvb-frontends/cxd2820r_core.c +++ b/drivers/media/dvb-frontends/cxd2820r_core.c @@ -21,21 +21,31 @@ #include "cxd2820r_priv.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + /* write multiple registers */ static int cxd2820r_wr_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg, u8 *val, int len) { int ret; - u8 buf[len+1]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { .addr = i2c, .flags = 0, - .len = sizeof(buf), + .len = len + 1, .buf = buf, } }; + if (1 + len > sizeof(buf)) { + dev_warn(&priv->i2c->dev, + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, len); + return -EINVAL; + } + buf[0] = reg; memcpy(&buf[1], val, len); @@ -55,7 +65,7 @@ static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg, u8 *val, int len) { int ret; - u8 buf[len]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[2] = { { .addr = i2c, @@ -65,11 +75,18 @@ static int cxd2820r_rd_regs_i2c(struct cxd2820r_priv *priv, u8 i2c, u8 reg, }, { .addr = i2c, .flags = I2C_M_RD, - .len = sizeof(buf), + .len = len, .buf = buf, } }; + if (len > sizeof(buf)) { + dev_warn(&priv->i2c->dev, + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, len); + return -EINVAL; + } + ret = i2c_transfer(priv->i2c, msg, 2); if (ret == 2) { memcpy(val, buf, len); diff --git a/drivers/media/dvb-frontends/dib8000.c b/drivers/media/dvb-frontends/dib8000.c index a54182dd0e91..362de38a7d8e 100644 --- a/drivers/media/dvb-frontends/dib8000.c +++ b/drivers/media/dvb-frontends/dib8000.c @@ -157,15 +157,10 @@ static u16 dib8000_i2c_read16(struct i2c_device *i2c, u16 reg) 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[1] = reg & 0xff; @@ -183,6 +178,21 @@ static u16 dib8000_read_word(struct dib8000_state *state, u16 reg) dprintk("i2c read error on %d", reg); ret = (state->i2c_read_buffer[0] << 8) | state->i2c_read_buffer[1]; + + 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; + } + + ret = __dib8000_read_word(state, reg); + mutex_unlock(&state->i2c_buffer_lock); return ret; @@ -192,8 +202,15 @@ static u32 dib8000_read32(struct dib8000_state *state, u16 reg) { u16 rw[2]; - rw[0] = dib8000_read_word(state, reg + 0); - rw[1] = dib8000_read_word(state, reg + 1); + if (mutex_lock_interruptible(&state->i2c_buffer_lock) < 0) { + dprintk("could not acquire lock"); + return 0; + } + + rw[0] = __dib8000_read_word(state, reg + 0); + rw[1] = __dib8000_read_word(state, reg + 1); + + mutex_unlock(&state->i2c_buffer_lock); return ((rw[0] << 16) | (rw[1])); } @@ -2445,7 +2462,8 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe) if (state->revision == 0x8090) internal = dib8000_read32(state, 23) / 1000; - if (state->autosearch_state == AS_SEARCHING_FFT) { + if ((state->revision >= 0x8002) && + (state->autosearch_state == AS_SEARCHING_FFT)) { dib8000_write_word(state, 37, 0x0065); /* P_ctrl_pha_off_max default values */ dib8000_write_word(state, 116, 0x0000); /* P_ana_gain to 0 */ @@ -2481,7 +2499,8 @@ static int dib8000_autosearch_start(struct dvb_frontend *fe) dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (1 << 13)); /* P_restart_ccg = 1 */ dib8000_write_word(state, 770, (dib8000_read_word(state, 770) & 0xdfff) | (0 << 13)); /* P_restart_ccg = 0 */ dib8000_write_word(state, 0, (dib8000_read_word(state, 0) & 0x7ff) | (0 << 15) | (1 << 13)); /* P_restart_search = 0; */ - } else if (state->autosearch_state == AS_SEARCHING_GUARD) { + } else if ((state->revision >= 0x8002) && + (state->autosearch_state == AS_SEARCHING_GUARD)) { c->transmission_mode = TRANSMISSION_MODE_8K; c->guard_interval = GUARD_INTERVAL_1_8; c->inversion = 0; @@ -2583,7 +2602,8 @@ static int dib8000_autosearch_irq(struct dvb_frontend *fe) struct dib8000_state *state = fe->demodulator_priv; u16 irq_pending = dib8000_read_word(state, 1284); - if (state->autosearch_state == AS_SEARCHING_FFT) { + if ((state->revision >= 0x8002) && + (state->autosearch_state == AS_SEARCHING_FFT)) { if (irq_pending & 0x1) { dprintk("dib8000_autosearch_irq: max correlation result available"); return 3; diff --git a/drivers/media/dvb-frontends/itd1000.c b/drivers/media/dvb-frontends/itd1000.c index c1c3400b2173..cadcae4cff89 100644 --- a/drivers/media/dvb-frontends/itd1000.c +++ b/drivers/media/dvb-frontends/itd1000.c @@ -31,6 +31,9 @@ #include "itd1000.h" #include "itd1000_priv.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + static int debug; module_param(debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); @@ -52,10 +55,18 @@ MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off)."); /* don't write more than one byte with flexcop behind */ static int itd1000_write_regs(struct itd1000_state *state, u8 reg, u8 v[], u8 len) { - u8 buf[1+len]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg = { .addr = state->cfg->i2c_address, .flags = 0, .buf = buf, .len = len+1 }; + + if (1 + len > sizeof(buf)) { + printk(KERN_WARNING + "itd1000: i2c wr reg=%04x: len=%d is too big!\n", + reg, len); + return -EINVAL; + } + buf[0] = reg; memcpy(&buf[1], v, len); diff --git a/drivers/media/dvb-frontends/m88rs2000.c b/drivers/media/dvb-frontends/m88rs2000.c index 4da5272075cb..02699c111019 100644 --- a/drivers/media/dvb-frontends/m88rs2000.c +++ b/drivers/media/dvb-frontends/m88rs2000.c @@ -110,28 +110,94 @@ static u8 m88rs2000_readreg(struct m88rs2000_state *state, u8 reg) return b1[0]; } +static u32 m88rs2000_get_mclk(struct dvb_frontend *fe) +{ + struct m88rs2000_state *state = fe->demodulator_priv; + u32 mclk; + u8 reg; + /* Must not be 0x00 or 0xff */ + reg = m88rs2000_readreg(state, 0x86); + if (!reg || reg == 0xff) + return 0; + + reg /= 2; + reg += 1; + + mclk = (u32)(reg * RS2000_FE_CRYSTAL_KHZ + 28 / 2) / 28; + + return mclk; +} + +static int m88rs2000_set_carrieroffset(struct dvb_frontend *fe, s16 offset) +{ + struct m88rs2000_state *state = fe->demodulator_priv; + u32 mclk; + s32 tmp; + u8 reg; + int ret; + + mclk = m88rs2000_get_mclk(fe); + if (!mclk) + return -EINVAL; + + tmp = (offset * 4096 + (s32)mclk / 2) / (s32)mclk; + if (tmp < 0) + tmp += 4096; + + /* Carrier Offset */ + ret = m88rs2000_writereg(state, 0x9c, (u8)(tmp >> 4)); + + reg = m88rs2000_readreg(state, 0x9d); + reg &= 0xf; + reg |= (u8)(tmp & 0xf) << 4; + + ret |= m88rs2000_writereg(state, 0x9d, reg); + + return ret; +} + static int m88rs2000_set_symbolrate(struct dvb_frontend *fe, u32 srate) { struct m88rs2000_state *state = fe->demodulator_priv; int ret; - u32 temp; + u64 temp; + u32 mclk; u8 b[3]; if ((srate < 1000000) || (srate > 45000000)) return -EINVAL; + mclk = m88rs2000_get_mclk(fe); + if (!mclk) + return -EINVAL; + temp = srate / 1000; - temp *= 11831; - temp /= 68; - temp -= 3; + temp *= 1 << 24; + + do_div(temp, mclk); b[0] = (u8) (temp >> 16) & 0xff; b[1] = (u8) (temp >> 8) & 0xff; b[2] = (u8) temp & 0xff; + ret = m88rs2000_writereg(state, 0x93, b[2]); ret |= m88rs2000_writereg(state, 0x94, b[1]); ret |= m88rs2000_writereg(state, 0x95, b[0]); + if (srate > 10000000) + ret |= m88rs2000_writereg(state, 0xa0, 0x20); + else + ret |= m88rs2000_writereg(state, 0xa0, 0x60); + + ret |= m88rs2000_writereg(state, 0xa1, 0xe0); + + if (srate > 12000000) + ret |= m88rs2000_writereg(state, 0xa3, 0x20); + else if (srate > 2800000) + ret |= m88rs2000_writereg(state, 0xa3, 0x98); + else + ret |= m88rs2000_writereg(state, 0xa3, 0x90); + deb_info("m88rs2000: m88rs2000_set_symbolrate\n"); return ret; } @@ -261,8 +327,6 @@ struct inittab m88rs2000_shutdown[] = { struct inittab fe_reset[] = { {DEMOD_WRITE, 0x00, 0x01}, - {DEMOD_WRITE, 0xf1, 0xbf}, - {DEMOD_WRITE, 0x00, 0x01}, {DEMOD_WRITE, 0x20, 0x81}, {DEMOD_WRITE, 0x21, 0x80}, {DEMOD_WRITE, 0x10, 0x33}, @@ -305,9 +369,6 @@ struct inittab fe_trigger[] = { {DEMOD_WRITE, 0x9b, 0x64}, {DEMOD_WRITE, 0x9e, 0x00}, {DEMOD_WRITE, 0x9f, 0xf8}, - {DEMOD_WRITE, 0xa0, 0x20}, - {DEMOD_WRITE, 0xa1, 0xe0}, - {DEMOD_WRITE, 0xa3, 0x38}, {DEMOD_WRITE, 0x98, 0xff}, {DEMOD_WRITE, 0xc0, 0x0f}, {DEMOD_WRITE, 0x89, 0x01}, @@ -540,9 +601,8 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) struct dtv_frontend_properties *c = &fe->dtv_property_cache; fe_status_t status; int i, ret = 0; - s32 tmp; u32 tuner_freq; - u16 offset = 0; + s16 offset = 0; u8 reg; state->no_lock_count = 0; @@ -567,29 +627,26 @@ static int m88rs2000_set_frontend(struct dvb_frontend *fe) if (ret < 0) return -ENODEV; - offset = tuner_freq - c->frequency; - - /* calculate offset assuming 96000kHz*/ - tmp = offset; - tmp *= 65536; - - tmp = (2 * tmp + 96000) / (2 * 96000); - if (tmp < 0) - tmp += 65536; + offset = (s16)((s32)tuner_freq - c->frequency); - offset = tmp & 0xffff; + /* default mclk value 96.4285 * 2 * 1000 = 192857 */ + if (((c->frequency % 192857) >= (192857 - 3000)) || + (c->frequency % 192857) <= 3000) + ret = m88rs2000_writereg(state, 0x86, 0xc2); + else + ret = m88rs2000_writereg(state, 0x86, 0xc6); - ret = m88rs2000_writereg(state, 0x9a, 0x30); - /* Unknown usually 0xc6 sometimes 0xc1 */ - reg = m88rs2000_readreg(state, 0x86); - ret |= m88rs2000_writereg(state, 0x86, reg); - /* Offset lower nibble always 0 */ - ret |= m88rs2000_writereg(state, 0x9c, (offset >> 8)); - ret |= m88rs2000_writereg(state, 0x9d, offset & 0xf0); + ret |= m88rs2000_set_carrieroffset(fe, offset); + if (ret < 0) + return -ENODEV; + /* Reset demod by symbol rate */ + if (c->symbol_rate > 27500000) + ret = m88rs2000_writereg(state, 0xf1, 0xa4); + else + ret = m88rs2000_writereg(state, 0xf1, 0xbf); - /* Reset Demod */ - ret = m88rs2000_tab_set(state, fe_reset); + ret |= m88rs2000_tab_set(state, fe_reset); if (ret < 0) return -ENODEV; diff --git a/drivers/media/dvb-frontends/m88rs2000.h b/drivers/media/dvb-frontends/m88rs2000.h index 14ce31e76ae6..0a50ea90736b 100644 --- a/drivers/media/dvb-frontends/m88rs2000.h +++ b/drivers/media/dvb-frontends/m88rs2000.h @@ -53,6 +53,8 @@ static inline struct dvb_frontend *m88rs2000_attach( } #endif /* CONFIG_DVB_M88RS2000 */ +#define RS2000_FE_CRYSTAL_KHZ 27000 + enum { DEMOD_WRITE = 0x1, WRITE_DELAY = 0x10, diff --git a/drivers/media/dvb-frontends/mb86a20s.c b/drivers/media/dvb-frontends/mb86a20s.c index 856374bd3676..2c7217fb1415 100644 --- a/drivers/media/dvb-frontends/mb86a20s.c +++ b/drivers/media/dvb-frontends/mb86a20s.c @@ -157,7 +157,6 @@ static struct regdata mb86a20s_init2[] = { { 0x45, 0x04 }, /* CN symbol 4 */ { 0x48, 0x04 }, /* CN manual mode */ - { 0x50, 0xd5 }, { 0x51, 0x01 }, /* Serial */ { 0x50, 0xd6 }, { 0x51, 0x1f }, { 0x50, 0xd2 }, { 0x51, 0x03 }, { 0x50, 0xd7 }, { 0x51, 0xbf }, @@ -1860,16 +1859,15 @@ static int mb86a20s_initfe(struct dvb_frontend *fe) dev_dbg(&state->i2c->dev, "%s: IF=%d, IF reg=0x%06llx\n", __func__, state->if_freq, (long long)pll); - if (!state->config->is_serial) { + if (!state->config->is_serial) regD5 &= ~1; - rc = mb86a20s_writereg(state, 0x50, 0xd5); - if (rc < 0) - goto err; - rc = mb86a20s_writereg(state, 0x51, regD5); - if (rc < 0) - goto err; - } + rc = mb86a20s_writereg(state, 0x50, 0xd5); + if (rc < 0) + goto err; + rc = mb86a20s_writereg(state, 0x51, regD5); + if (rc < 0) + goto err; rc = mb86a20s_writeregdata(state, mb86a20s_init2); if (rc < 0) diff --git a/drivers/media/dvb-frontends/mt312.c b/drivers/media/dvb-frontends/mt312.c index ec388c1d6913..a74ac0ddb833 100644 --- a/drivers/media/dvb-frontends/mt312.c +++ b/drivers/media/dvb-frontends/mt312.c @@ -36,6 +36,8 @@ #include "mt312_priv.h" #include "mt312.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 struct mt312_state { struct i2c_adapter *i2c; @@ -96,9 +98,15 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg, const u8 *src, const size_t count) { int ret; - u8 buf[count + 1]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg; + if (1 + count > sizeof(buf)) { + printk(KERN_WARNING + "mt312: write: len=%zd is too big!\n", count); + return -EINVAL; + } + if (debug) { int i; dprintk("W(%d):", reg & 0x7f); diff --git a/drivers/media/dvb-frontends/nxt200x.c b/drivers/media/dvb-frontends/nxt200x.c index 8e288940a61f..4bf057544607 100644 --- a/drivers/media/dvb-frontends/nxt200x.c +++ b/drivers/media/dvb-frontends/nxt200x.c @@ -39,6 +39,9 @@ */ #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 256 + #define NXT2002_DEFAULT_FIRMWARE "dvb-fe-nxt2002.fw" #define NXT2004_DEFAULT_FIRMWARE "dvb-fe-nxt2004.fw" #define CRC_CCIT_MASK 0x1021 @@ -95,10 +98,16 @@ static int i2c_readbytes(struct nxt200x_state *state, u8 addr, u8 *buf, u8 len) static int nxt200x_writebytes (struct nxt200x_state* state, u8 reg, const u8 *buf, u8 len) { - u8 buf2 [len+1]; + u8 buf2[MAX_XFER_SIZE]; int err; struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf2, .len = len + 1 }; + if (1 + len > sizeof(buf2)) { + pr_warn("%s: i2c wr reg=%04x: len=%d is too big!\n", + __func__, reg, len); + return -EINVAL; + } + buf2[0] = reg; memcpy(&buf2[1], buf, len); diff --git a/drivers/media/dvb-frontends/rtl2830.c b/drivers/media/dvb-frontends/rtl2830.c index 362d26d11e82..7efb796c472c 100644 --- a/drivers/media/dvb-frontends/rtl2830.c +++ b/drivers/media/dvb-frontends/rtl2830.c @@ -27,20 +27,30 @@ #include "rtl2830_priv.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + /* write multiple hardware registers */ static int rtl2830_wr(struct rtl2830_priv *priv, u8 reg, const u8 *val, int len) { int ret; - u8 buf[1+len]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { .addr = priv->cfg.i2c_addr, .flags = 0, - .len = 1+len, + .len = 1 + len, .buf = buf, } }; + if (1 + len > sizeof(buf)) { + dev_warn(&priv->i2c->dev, + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, len); + return -EINVAL; + } + buf[0] = reg; memcpy(&buf[1], val, len); diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c index facb84841518..b8dd0a135461 100644 --- a/drivers/media/dvb-frontends/rtl2832.c +++ b/drivers/media/dvb-frontends/rtl2832.c @@ -22,6 +22,9 @@ #include "dvb_math.h" #include <linux/bitops.h> +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + int rtl2832_debug; module_param_named(debug, rtl2832_debug, int, 0644); MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off)."); @@ -162,16 +165,23 @@ static const struct rtl2832_reg_entry registers[] = { static int rtl2832_wr(struct rtl2832_priv *priv, u8 reg, u8 *val, int len) { int ret; - u8 buf[1+len]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { .addr = priv->cfg.i2c_addr, .flags = 0, - .len = 1+len, + .len = 1 + len, .buf = buf, } }; + if (1 + len > sizeof(buf)) { + dev_warn(&priv->i2c->dev, + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, len); + return -EINVAL; + } + buf[0] = reg; memcpy(&buf[1], val, len); diff --git a/drivers/media/dvb-frontends/s5h1420.c b/drivers/media/dvb-frontends/s5h1420.c index e2fec9ebf947..93eeaf7118fd 100644 --- a/drivers/media/dvb-frontends/s5h1420.c +++ b/drivers/media/dvb-frontends/s5h1420.c @@ -836,9 +836,16 @@ static u32 s5h1420_tuner_i2c_func(struct i2c_adapter *adapter) static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num) { struct s5h1420_state *state = i2c_get_adapdata(i2c_adap); - struct i2c_msg m[1 + num]; + struct i2c_msg m[3]; u8 tx_open[2] = { CON_1, state->CON_1_val | 1 }; /* repeater stops once there was a stop condition */ + if (1 + num > ARRAY_SIZE(m)) { + printk(KERN_WARNING + "%s: i2c xfer: num=%d is too big!\n", + KBUILD_MODNAME, num); + return -EOPNOTSUPP; + } + memset(m, 0, sizeof(struct i2c_msg) * (1 + num)); m[0].addr = state->config->demod_address; @@ -847,7 +854,7 @@ static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c memcpy(&m[1], msg, sizeof(struct i2c_msg) * num); - return i2c_transfer(state->i2c, m, 1+num) == 1 + num ? num : -EIO; + return i2c_transfer(state->i2c, m, 1 + num) == 1 + num ? num : -EIO; } static struct i2c_algorithm s5h1420_tuner_i2c_algo = { diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c index cc278b3d6d5a..2a979cfac146 100644 --- a/drivers/media/dvb-frontends/stb0899_drv.c +++ b/drivers/media/dvb-frontends/stb0899_drv.c @@ -32,6 +32,9 @@ #include "stb0899_priv.h" #include "stb0899_reg.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + static unsigned int verbose = 0;//1; module_param(verbose, int, 0644); @@ -499,7 +502,7 @@ err: int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, u32 count) { int ret; - u8 buf[2 + count]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg i2c_msg = { .addr = state->config->demod_address, .flags = 0, @@ -507,6 +510,13 @@ int stb0899_write_regs(struct stb0899_state *state, unsigned int reg, u8 *data, .len = 2 + count }; + if (2 + count > sizeof(buf)) { + printk(KERN_WARNING + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, count); + return -EINVAL; + } + buf[0] = reg >> 8; buf[1] = reg & 0xff; memcpy(&buf[2], data, count); diff --git a/drivers/media/dvb-frontends/stb6100.c b/drivers/media/dvb-frontends/stb6100.c index 45f9523f968f..cea175d19890 100644 --- a/drivers/media/dvb-frontends/stb6100.c +++ b/drivers/media/dvb-frontends/stb6100.c @@ -31,6 +31,8 @@ static unsigned int verbose; module_param(verbose, int, 0644); +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 #define FE_ERROR 0 #define FE_NOTICE 1 @@ -183,7 +185,7 @@ static int stb6100_read_reg(struct stb6100_state *state, u8 reg) static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len) { int rc; - u8 cmdbuf[len + 1]; + u8 cmdbuf[MAX_XFER_SIZE]; struct i2c_msg msg = { .addr = state->config->tuner_address, .flags = 0, @@ -191,6 +193,13 @@ static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int st .len = len + 1 }; + if (1 + len > sizeof(buf)) { + printk(KERN_WARNING + "%s: i2c wr: len=%d is too big!\n", + KBUILD_MODNAME, len); + return -EINVAL; + } + if (unlikely(start < 1 || start + len > STB6100_NUMREGS)) { dprintk(verbose, FE_ERROR, 1, "Invalid register range %d:%d", start, len); diff --git a/drivers/media/dvb-frontends/stv0367.c b/drivers/media/dvb-frontends/stv0367.c index 0c8e45949b11..f6c7277999fe 100644 --- a/drivers/media/dvb-frontends/stv0367.c +++ b/drivers/media/dvb-frontends/stv0367.c @@ -33,6 +33,9 @@ #include "stv0367_regs.h" #include "stv0367_priv.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + static int stvdebug; module_param_named(debug, stvdebug, int, 0644); @@ -767,7 +770,7 @@ static struct st_register def0367cab[STV0367CAB_NBREGS] = { static int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len) { - u8 buf[len + 2]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, @@ -776,6 +779,14 @@ int stv0367_writeregs(struct stv0367_state *state, u16 reg, u8 *data, int len) }; int ret; + if (2 + len > sizeof(buf)) { + printk(KERN_WARNING + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, len); + return -EINVAL; + } + + buf[0] = MSB(reg); buf[1] = LSB(reg); memcpy(buf + 2, data, len); diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c index 56d470ad5a82..23e872f84742 100644 --- a/drivers/media/dvb-frontends/stv090x.c +++ b/drivers/media/dvb-frontends/stv090x.c @@ -35,6 +35,9 @@ #include "stv090x.h" #include "stv090x_priv.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + static unsigned int verbose; module_param(verbose, int, 0644); @@ -722,9 +725,16 @@ static int stv090x_write_regs(struct stv090x_state *state, unsigned int reg, u8 { const struct stv090x_config *config = state->config; int ret; - u8 buf[2 + count]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg i2c_msg = { .addr = config->address, .flags = 0, .buf = buf, .len = 2 + count }; + if (2 + count > sizeof(buf)) { + printk(KERN_WARNING + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, count); + return -EINVAL; + } + buf[0] = reg >> 8; buf[1] = reg & 0xff; memcpy(&buf[2], data, count); diff --git a/drivers/media/dvb-frontends/stv6110.c b/drivers/media/dvb-frontends/stv6110.c index 20b5fa92c53e..b1425830a24e 100644 --- a/drivers/media/dvb-frontends/stv6110.c +++ b/drivers/media/dvb-frontends/stv6110.c @@ -30,6 +30,9 @@ #include "stv6110.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + static int debug; struct stv6110_priv { @@ -68,7 +71,7 @@ static int stv6110_write_regs(struct dvb_frontend *fe, u8 buf[], { struct stv6110_priv *priv = fe->tuner_priv; int rc; - u8 cmdbuf[len + 1]; + u8 cmdbuf[MAX_XFER_SIZE]; struct i2c_msg msg = { .addr = priv->i2c_address, .flags = 0, @@ -78,6 +81,13 @@ static int stv6110_write_regs(struct dvb_frontend *fe, u8 buf[], dprintk("%s\n", __func__); + if (1 + len > sizeof(cmdbuf)) { + printk(KERN_WARNING + "%s: i2c wr: len=%d is too big!\n", + KBUILD_MODNAME, len); + return -EINVAL; + } + if (start + len > 8) return -EINVAL; diff --git a/drivers/media/dvb-frontends/stv6110x.c b/drivers/media/dvb-frontends/stv6110x.c index f36cab12bdc7..e66154e5c1d7 100644 --- a/drivers/media/dvb-frontends/stv6110x.c +++ b/drivers/media/dvb-frontends/stv6110x.c @@ -32,6 +32,9 @@ #include "stv6110x.h" #include "stv6110x_priv.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + static unsigned int verbose; module_param(verbose, int, 0644); MODULE_PARM_DESC(verbose, "Set Verbosity level"); @@ -61,7 +64,8 @@ static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 da { int ret; const struct stv6110x_config *config = stv6110x->config; - u8 buf[len + 1]; + u8 buf[MAX_XFER_SIZE]; + struct i2c_msg msg = { .addr = config->addr, .flags = 0, @@ -69,6 +73,13 @@ static int stv6110x_write_regs(struct stv6110x_state *stv6110x, int start, u8 da .len = len + 1 }; + if (1 + len > sizeof(buf)) { + printk(KERN_WARNING + "%s: i2c wr: len=%d is too big!\n", + KBUILD_MODNAME, len); + return -EINVAL; + } + if (start + len > 8) return -EINVAL; diff --git a/drivers/media/dvb-frontends/tda10071.c b/drivers/media/dvb-frontends/tda10071.c index 2521f7e23018..36eb27d3fdf1 100644 --- a/drivers/media/dvb-frontends/tda10071.c +++ b/drivers/media/dvb-frontends/tda10071.c @@ -20,6 +20,9 @@ #include "tda10071_priv.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + static struct dvb_frontend_ops tda10071_ops; /* write multiple registers */ @@ -27,16 +30,23 @@ static int tda10071_wr_regs(struct tda10071_priv *priv, u8 reg, u8 *val, int len) { int ret; - u8 buf[len+1]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[1] = { { .addr = priv->cfg.demod_i2c_addr, .flags = 0, - .len = sizeof(buf), + .len = 1 + len, .buf = buf, } }; + if (1 + len > sizeof(buf)) { + dev_warn(&priv->i2c->dev, + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, len); + return -EINVAL; + } + buf[0] = reg; memcpy(&buf[1], val, len); @@ -56,7 +66,7 @@ static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val, int len) { int ret; - u8 buf[len]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg[2] = { { .addr = priv->cfg.demod_i2c_addr, @@ -66,11 +76,18 @@ static int tda10071_rd_regs(struct tda10071_priv *priv, u8 reg, u8 *val, }, { .addr = priv->cfg.demod_i2c_addr, .flags = I2C_M_RD, - .len = sizeof(buf), + .len = len, .buf = buf, } }; + if (len > sizeof(buf)) { + dev_warn(&priv->i2c->dev, + "%s: i2c wr reg=%04x: len=%d is too big!\n", + KBUILD_MODNAME, reg, len); + return -EINVAL; + } + ret = i2c_transfer(priv->i2c, msg, 2); if (ret == 2) { memcpy(val, buf, len); diff --git a/drivers/media/dvb-frontends/tda18271c2dd.c b/drivers/media/dvb-frontends/tda18271c2dd.c index d281f77d5c28..2c54586ac07f 100644 --- a/drivers/media/dvb-frontends/tda18271c2dd.c +++ b/drivers/media/dvb-frontends/tda18271c2dd.c @@ -34,6 +34,9 @@ #include "dvb_frontend.h" #include "tda18271c2dd.h" +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + struct SStandardParam { s32 m_IFFrequency; u32 m_BandWidth; @@ -139,11 +142,18 @@ static int i2c_write(struct i2c_adapter *adap, u8 adr, u8 *data, int len) static int WriteRegs(struct tda_state *state, u8 SubAddr, u8 *Regs, u16 nRegs) { - u8 data[nRegs+1]; + u8 data[MAX_XFER_SIZE]; + + if (1 + nRegs > sizeof(data)) { + printk(KERN_WARNING + "%s: i2c wr: len=%d is too big!\n", + KBUILD_MODNAME, nRegs); + return -EINVAL; + } data[0] = SubAddr; memcpy(data + 1, Regs, nRegs); - return i2c_write(state->i2c, state->adr, data, nRegs+1); + return i2c_write(state->i2c, state->adr, data, nRegs + 1); } static int WriteReg(struct tda_state *state, u8 SubAddr, u8 Reg) diff --git a/drivers/media/dvb-frontends/zl10039.c b/drivers/media/dvb-frontends/zl10039.c index eff9c5fde50a..91b6b2e9b792 100644 --- a/drivers/media/dvb-frontends/zl10039.c +++ b/drivers/media/dvb-frontends/zl10039.c @@ -30,6 +30,9 @@ static int debug; +/* Max transfer size done by I2C transfer functions */ +#define MAX_XFER_SIZE 64 + #define dprintk(args...) \ do { \ if (debug) \ @@ -98,7 +101,7 @@ static int zl10039_write(struct zl10039_state *state, const enum zl10039_reg_addr reg, const u8 *src, const size_t count) { - u8 buf[count + 1]; + u8 buf[MAX_XFER_SIZE]; struct i2c_msg msg = { .addr = state->i2c_addr, .flags = 0, @@ -106,6 +109,13 @@ static int zl10039_write(struct zl10039_state *state, .len = count + 1, }; + if (1 + count > sizeof(buf)) { + printk(KERN_WARNING + "%s: i2c wr reg=%04x: len=%zd is too big!\n", + KBUILD_MODNAME, reg, count); + return -EINVAL; + } + dprintk("%s\n", __func__); /* Write register address and data in one go */ buf[0] = reg; |