diff options
author | Stephen Rothwell <sfr@canb.auug.org.au> | 2014-10-14 10:52:47 +1100 |
---|---|---|
committer | Stephen Rothwell <sfr@canb.auug.org.au> | 2014-10-14 10:52:47 +1100 |
commit | 59aa367b2512acb19a24423387e0649eb33fb290 (patch) | |
tree | 3bb4c5213681458885a7070452b6e7cdbd8ec400 /drivers | |
parent | 4534e2ebf503ccffbaa3fedad687501e40edfb3f (diff) | |
parent | 8f2f28bac3d1af2ee7b732666006b66c879396f0 (diff) |
Merge remote-tracking branch 'v4l-dvb/master'
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/dvb-frontends/Kconfig | 1 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/si2165.c | 105 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/si2165_priv.h | 2 | ||||
-rw-r--r-- | drivers/media/dvb-frontends/si2168.c | 2 |
4 files changed, 67 insertions, 43 deletions
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig index 5a134547e325..804da4e64ad3 100644 --- a/drivers/media/dvb-frontends/Kconfig +++ b/drivers/media/dvb-frontends/Kconfig @@ -66,6 +66,7 @@ config DVB_TDA18271C2DD config DVB_SI2165 tristate "Silicon Labs si2165 based" depends on DVB_CORE && I2C + select CRC_ITU_T default m if !MEDIA_SUBDRV_AUTOSELECT help A DVB-C/T demodulator. diff --git a/drivers/media/dvb-frontends/si2165.c b/drivers/media/dvb-frontends/si2165.c index 98ddb49ad52b..b64a59c281c7 100644 --- a/drivers/media/dvb-frontends/si2165.c +++ b/drivers/media/dvb-frontends/si2165.c @@ -25,6 +25,7 @@ #include <linux/string.h> #include <linux/slab.h> #include <linux/firmware.h> +#include <linux/crc-itu-t.h> #include "dvb_frontend.h" #include "dvb_math.h" @@ -327,8 +328,50 @@ static int si2165_wait_init_done(struct si2165_state *state) return ret; } +static int si2165_count_fw_blocks(struct si2165_state *state, const u8 *data, + u32 len) +{ + int block_count = 0; + u32 offset = 0; + + if (len % 4 != 0) { + dev_warn(&state->i2c->dev, "%s: firmware size is not multiple of 4\n", + KBUILD_MODNAME); + return -EINVAL; + } + + while (offset + 4 <= len) { + u8 wordcount = data[offset]; + + if (wordcount < 1 || data[offset+1] || + data[offset+2] || data[offset+3]) { + dev_warn(&state->i2c->dev, + "%s: bad fw data[0..3] = %*ph at offset=%d\n", + KBUILD_MODNAME, 4, data, offset); + return -EINVAL; + } + offset += 8 + 4 * wordcount; + ++block_count; + } + if (offset != len) { + dev_warn(&state->i2c->dev, + "%s: firmware length does not match content, len=%d, offset=%d\n", + KBUILD_MODNAME, len, offset); + return -EINVAL; + } + if (block_count < 6) { + dev_err(&state->i2c->dev, "%s: firmware is too short: Only %d blocks\n", + KBUILD_MODNAME, block_count); + return -EINVAL; + } + block_count -= 6; + dev_info(&state->i2c->dev, "%s: si2165_upload_firmware counted %d main blocks\n", + KBUILD_MODNAME, block_count); + return block_count; +} + static int si2165_upload_firmware_block(struct si2165_state *state, - const u8 *data, u32 len, u32 *poffset, u32 block_count) + const u8 *data, u32 len, u32 *poffset, u32 block_count, u16 *crc) { int ret; u8 buf_ctrl[4] = { 0x00, 0x00, 0x00, 0xc0 }; @@ -374,6 +417,10 @@ static int si2165_upload_firmware_block(struct si2165_state *state, offset += 8; while (wordcount > 0) { + *crc = crc_itu_t_byte(*crc, *(data+offset+3)); + *crc = crc_itu_t_byte(*crc, *(data+offset+2)); + *crc = crc_itu_t_byte(*crc, *(data+offset+1)); + *crc = crc_itu_t_byte(*crc, *(data+offset+0)); ret = si2165_write(state, 0x36c, data+offset, 4); if (ret < 0) goto error; @@ -408,10 +455,9 @@ static int si2165_upload_firmware(struct si2165_state *state) u8 *fw_file; const u8 *data; u32 len; - u32 offset; - u8 patch_version; - u8 block_count; - u16 crc_expected; + u32 offset = 0; + int main_block_count; + u16 crc = 0; switch (state->chip_revcode) { case 0x03: /* revision D */ @@ -437,32 +483,13 @@ static int si2165_upload_firmware(struct si2165_state *state) dev_info(&state->i2c->dev, "%s: downloading firmware from file '%s' size=%d\n", KBUILD_MODNAME, fw_file, len); - if (len % 4 != 0) { - dev_warn(&state->i2c->dev, "%s: firmware size is not multiple of 4\n", - KBUILD_MODNAME); - ret = -EINVAL; - goto error; - } - - /* check header (8 bytes) */ - if (len < 8) { - dev_warn(&state->i2c->dev, "%s: firmware header is missing\n", - KBUILD_MODNAME); - ret = -EINVAL; - goto error; - } - - if (data[0] != 1 || data[1] != 0) { - dev_warn(&state->i2c->dev, "%s: firmware file version is wrong\n", - KBUILD_MODNAME); - ret = -EINVAL; - goto error; + main_block_count = si2165_count_fw_blocks(state, data, len); + if (main_block_count < 0) { + dev_err(&state->i2c->dev, "%s: si2165_upload_firmware: cannot use firmware, skip\n", + KBUILD_MODNAME); + return main_block_count; } - patch_version = data[2]; - block_count = data[4]; - crc_expected = data[7] << 8 | data[6]; - /* start uploading fw */ /* boot/wdog status */ ret = si2165_writereg8(state, 0x0341, 0x00); @@ -488,17 +515,12 @@ static int si2165_upload_firmware(struct si2165_state *state) if (ret < 0) goto error; - /* start right after the header */ - offset = 8; - - dev_info(&state->i2c->dev, "%s: si2165_upload_firmware extracted patch_version=0x%02x, block_count=0x%02x, crc_expected=0x%04x\n", - KBUILD_MODNAME, patch_version, block_count, crc_expected); - - ret = si2165_upload_firmware_block(state, data, len, &offset, 1); + ret = si2165_upload_firmware_block(state, data, len, &offset, 1, &crc); if (ret < 0) goto error; - ret = si2165_writereg8(state, 0x0344, patch_version); + /* patch version, just write a number different from the default 0x00 */ + ret = si2165_writereg8(state, 0x0344, 0x01); if (ret < 0) goto error; @@ -506,9 +528,10 @@ static int si2165_upload_firmware(struct si2165_state *state) ret = si2165_writereg8(state, 0x0379, 0x01); if (ret) return ret; + crc = 0; ret = si2165_upload_firmware_block(state, data, len, - &offset, block_count); + &offset, main_block_count, &crc); if (ret < 0) { dev_err(&state->i2c->dev, "%s: firmare could not be uploaded\n", @@ -521,15 +544,15 @@ static int si2165_upload_firmware(struct si2165_state *state) if (ret) goto error; - if (val16 != crc_expected) { + if (val16 != crc) { dev_err(&state->i2c->dev, "%s: firmware crc mismatch %04x != %04x\n", - KBUILD_MODNAME, val16, crc_expected); + KBUILD_MODNAME, val16, crc); ret = -EINVAL; goto error; } - ret = si2165_upload_firmware_block(state, data, len, &offset, 5); + ret = si2165_upload_firmware_block(state, data, len, &offset, 5, &crc); if (ret) goto error; diff --git a/drivers/media/dvb-frontends/si2165_priv.h b/drivers/media/dvb-frontends/si2165_priv.h index 2b70cf12cd79..52718c375843 100644 --- a/drivers/media/dvb-frontends/si2165_priv.h +++ b/drivers/media/dvb-frontends/si2165_priv.h @@ -18,6 +18,6 @@ #ifndef _DVB_SI2165_PRIV #define _DVB_SI2165_PRIV -#define SI2165_FIRMWARE_REV_D "dvb-demod-si2165.fw" +#define SI2165_FIRMWARE_REV_D "dvb-demod-si2165-d.fw" #endif /* _DVB_SI2165_PRIV */ diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c index 1cd93be281ed..e7cc5310e8a4 100644 --- a/drivers/media/dvb-frontends/si2168.c +++ b/drivers/media/dvb-frontends/si2168.c @@ -59,7 +59,7 @@ static int si2168_cmd_execute(struct si2168 *s, struct si2168_cmd *cmd) jiffies_to_msecs(jiffies) - (jiffies_to_msecs(timeout) - TIMEOUT)); - if (!((cmd->args[0] >> 7) & 0x01)) { + if (!(cmd->args[0] >> 7) & 0x01) { ret = -ETIMEDOUT; goto err_mutex_unlock; } |