diff options
author | Alex Woods <devnull@localhost> | 2004-01-04 22:07:57 +0000 |
---|---|---|
committer | Alex Woods <devnull@localhost> | 2004-01-04 22:07:57 +0000 |
commit | 539fe957e343be686be416ccf137396bca953e07 (patch) | |
tree | 1c485d88b18197077156cb4388b13c59b23bf3a7 /linux/drivers | |
parent | eaef046bcb06617776887ce5876c3bc4ffb60f2d (diff) | |
download | mediapointer-dvb-s2-539fe957e343be686be416ccf137396bca953e07.tar.gz mediapointer-dvb-s2-539fe957e343be686be416ccf137396bca953e07.tar.bz2 |
Apply Hans-Frieder Vogt's patch for calculating firmware CRCs.
Update ttusb-dec docs accordingly.
Add him to contributors file and correct a typo.
Diffstat (limited to 'linux/drivers')
-rw-r--r-- | linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c | 113 |
1 files changed, 94 insertions, 19 deletions
diff --git a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c index 2fcd2887b..75b9f3c10 100644 --- a/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c +++ b/linux/drivers/media/dvb/ttusb-dec/ttusb_dec.c @@ -20,6 +20,7 @@ */ #include <asm/semaphore.h> +#include <linux/crc32.h> #include <linux/list.h> #include <linux/module.h> #include <linux/pci.h> @@ -168,6 +169,19 @@ static struct dvb_frontend_info dec3000s_frontend_info = { FE_CAN_HIERARCHY_AUTO, }; +static u16 crc16(u16 crc, const u8 *buf, size_t len) +{ + u16 tmp; + + while (len--) { + crc ^= *buf++; + crc ^= (u8)crc >> 4; + tmp = (u8)crc; + crc ^= (tmp ^ (tmp << 1)) << 4; + } + return crc; +} + static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, int param_length, const u8 params[], int *result_length, u8 cmd_result[]) @@ -235,6 +249,40 @@ static int ttusb_dec_send_command(struct ttusb_dec *dec, const u8 command, } } +static int ttusb_dec_get_stb_state (struct ttusb_dec *dec, unsigned int *mode, + unsigned int *product, + unsigned int *version) +{ + u8 c[COMMAND_PACKET_SIZE]; + int c_length; + int result; + unsigned int tmp; + + dprintk("%s\n", __FUNCTION__); + + result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c); + if (result) + return result; + + if (c_length >= 0x0c) { + if (mode != NULL) { + memcpy(&tmp, c, 4); + *mode = ntohl(tmp); + } + if (product != NULL) { + memcpy(&tmp, &c[4], 4); + *product = ntohl(tmp); + } + if (version != NULL) { + memcpy(&tmp, &c[8], 4); + *version = ntohl(tmp); + } + return 0; + } else { + return -1; + } +} + static int ttusb_dec_av_pes2ts_cb(void *priv, unsigned char *data) { struct dvb_demux_feed *dvbdmxfeed = (struct dvb_demux_feed *)priv; @@ -1038,14 +1086,16 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) int i, j, actual_len, result, size, trans_count; u8 b0[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00 }; + 0x61, 0x00 }; u8 b1[] = { 0x61 }; u8 b[ARM_PACKET_SIZE]; + char idstring[21]; u8 *firmware = NULL; size_t firmware_size = 0; - u32 firmware_csum = 0; + u16 firmware_csum = 0; + u16 firmware_csum_ns; u32 firmware_size_nl; - u32 firmware_csum_nl; + u32 crc32_csum, crc32_check, tmp; #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,0) const struct firmware *fw_entry = NULL; #endif @@ -1061,29 +1111,47 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) firmware = fw_entry->data; firmware_size = fw_entry->size; -#endif +#else switch (dec->model) { case TTUSB_DEC2000T: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) firmware = &dsp_dec2000t[0]; firmware_size = sizeof(dsp_dec2000t); -#endif - firmware_csum = 0x1bc86100; break; case TTUSB_DEC3000S: -#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) firmware = &dsp_dec3000s[0]; firmware_size = sizeof(dsp_dec3000s); -#endif - firmware_csum = 0x00000000; break; } +#endif + + if (firmware_size < 60) { + printk("%s: firmware size too small for DSP code (%u < 60).\n", + __FUNCTION__, firmware_size); + return -1; + } + + /* a 32 bit checksum over the first 56 bytes of the DSP Code is stored + at offset 56 of file, so use it to check if the firmware file is + valid. */ + crc32_csum = crc32(~0L, firmware, 56) ^ ~0L; + memcpy(&tmp, &firmware[56], 4); + crc32_check = htonl(tmp); + if (crc32_csum != crc32_check) { + printk("%s: crc32 check of DSP code failed (calculated " + "0x%08x != 0x%08x in file), file invalid.\n", + __FUNCTION__, crc32_csum, crc32_check); + return -1; + } + memcpy(idstring, &firmware[36], 20); + idstring[20] = '\0'; + printk(KERN_INFO "ttusb_dec: found DSP code \"%s\".\n", idstring); firmware_size_nl = htonl(firmware_size); memcpy(b0, &firmware_size_nl, 4); - firmware_csum_nl = htonl(firmware_csum); - memcpy(&b0[6], &firmware_csum_nl, 4); + firmware_csum = crc16(~0, firmware, firmware_size) ^ ~0; + firmware_csum_ns = htons(firmware_csum); + memcpy(&b0[6], &firmware_csum_ns, 2); result = ttusb_dec_send_command(dec, 0x41, sizeof(b0), b0, NULL, NULL); @@ -1125,18 +1193,25 @@ static int ttusb_dec_boot_dsp(struct ttusb_dec *dec) static int ttusb_dec_init_stb(struct ttusb_dec *dec) { - u8 c[COMMAND_PACKET_SIZE]; - int c_length; int result; + unsigned int mode, product, version; dprintk("%s\n", __FUNCTION__); - result = ttusb_dec_send_command(dec, 0x08, 0, NULL, &c_length, c); + result = ttusb_dec_get_stb_state(dec, &mode, &product, &version); if (!result) { - if (c_length != 0x0c || (c_length == 0x0c && c[9] != 0x63)) + if (!mode) { + if (version == 0xABCDEFAB) + printk(KERN_INFO "ttusb_dec: no version " + "info in Firmware\n"); + else + printk(KERN_INFO "ttusb_dec: Firmware " + "%x.%02x%c%c\n", + version >> 24, (version >> 16) & 0xff, + (version >> 8) & 0xff, version & 0xff); return ttusb_dec_boot_dsp(dec); - else + } else return 0; } else @@ -1572,13 +1647,13 @@ static int ttusb_dec_probe(struct usb_interface *intf, case 0x1006: dec->model = TTUSB_DEC3000S; dec->model_name = "DEC3000-s"; - dec->firmware_name = "dvb-ttusb-dec-3000s-2.15a.fw"; + dec->firmware_name = "dvb-ttusb-dec-3000s.fw"; break; case 0x1008: dec->model = TTUSB_DEC2000T; dec->model_name = "DEC2000-t"; - dec->firmware_name = "dvb-ttusb-dec-2000t-2.15a.fw"; + dec->firmware_name = "dvb-ttusb-dec-2000t.fw"; break; } |