diff options
Diffstat (limited to 'drivers/media/dvb-frontends/af9033.c')
| -rw-r--r-- | drivers/media/dvb-frontends/af9033.c | 82 |
1 files changed, 78 insertions, 4 deletions
diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c index a777b4b944e..be4bec2a964 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; @@ -972,10 +989,62 @@ err: return ret; } +static int af9033_pid_filter_ctrl(struct dvb_frontend *fe, int onoff) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + + dev_dbg(&state->i2c->dev, "%s: onoff=%d\n", __func__, onoff); + + ret = af9033_wr_reg_mask(state, 0x80f993, onoff, 0x01); + if (ret < 0) + goto err; + + return 0; + +err: + dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + +static int af9033_pid_filter(struct dvb_frontend *fe, int index, u16 pid, int onoff) +{ + struct af9033_state *state = fe->demodulator_priv; + int ret; + u8 wbuf[2] = {(pid >> 0) & 0xff, (pid >> 8) & 0xff}; + + dev_dbg(&state->i2c->dev, "%s: index=%d pid=%04x onoff=%d\n", + __func__, index, pid, onoff); + + if (pid > 0x1fff) + return 0; + + ret = af9033_wr_regs(state, 0x80f996, wbuf, 2); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x80f994, onoff); + if (ret < 0) + goto err; + + ret = af9033_wr_reg(state, 0x80f995, index); + if (ret < 0) + goto err; + + return 0; + +err: + dev_dbg(&state->i2c->dev, "%s: failed=%d\n", __func__, ret); + + return ret; +} + static struct dvb_frontend_ops af9033_ops; struct dvb_frontend *af9033_attach(const struct af9033_config *config, - struct i2c_adapter *i2c) + struct i2c_adapter *i2c, + struct af9033_ops *ops) { int ret; struct af9033_state *state; @@ -1050,6 +1119,11 @@ struct dvb_frontend *af9033_attach(const struct af9033_config *config, memcpy(&state->fe.ops, &af9033_ops, sizeof(struct dvb_frontend_ops)); state->fe.demodulator_priv = state; + if (ops) { + ops->pid_filter = af9033_pid_filter; + ops->pid_filter_ctrl = af9033_pid_filter_ctrl; + } + return &state->fe; err: |
