diff options
Diffstat (limited to 'v4l2-apps/util/xc3028-firmware/firmware-tool.c')
-rw-r--r-- | v4l2-apps/util/xc3028-firmware/firmware-tool.c | 471 |
1 files changed, 388 insertions, 83 deletions
diff --git a/v4l2-apps/util/xc3028-firmware/firmware-tool.c b/v4l2-apps/util/xc3028-firmware/firmware-tool.c index a8e6d0c01..28ae70bb2 100644 --- a/v4l2-apps/util/xc3028-firmware/firmware-tool.c +++ b/v4l2-apps/util/xc3028-firmware/firmware-tool.c @@ -3,6 +3,10 @@ Copyright (C) 2007 Michel Ludwig <michel.ludwig@gmail.com> + Copyright (C) 2007, 2008 Mauro Carvalho Chehab <mchehab@infradead.org> + - Improve --list command + - Add --seek command + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation version 2 @@ -31,6 +35,7 @@ #include "../../../linux/drivers/media/video/tuner-xc2028-types.h" #include "../../../linux/include/linux/videodev2.h" +#include "extract_head.h" #include "standards.h" #define LIST_ACTION (1<<0) @@ -38,6 +43,7 @@ #define DELETE_ACTION (1<<2) #define SET_TYPE_ACTION (1<<3) #define SET_ID_ACTION (1<<4) +#define SEEK_FIRM_ACTION (1<<5) struct firmware_description { __u32 type; @@ -287,74 +293,74 @@ void write_firmware_file(const char* filename, struct firmware *f) { close(fd); } -void dump_firm_type(unsigned int type) +void dump_firm_type(FILE *fp, unsigned int type) { if (type & SCODE) - printf("SCODE FW "); + fprintf(fp, "SCODE FW "); else if (type & BASE) - printf("BASE FW "); + fprintf(fp, "BASE FW "); else - printf("STD FW "); + fprintf(fp, "STD FW "); if (type & F8MHZ) - printf("F8MHZ "); + fprintf(fp, "F8MHZ "); if (type & MTS) - printf("MTS "); + fprintf(fp, "MTS "); if (type & D2620) - printf("D2620 "); + fprintf(fp, "D2620 "); if (type & D2633) - printf("D2633 "); + fprintf(fp, "D2633 "); if (type & DTV6) - printf("DTV6 "); + fprintf(fp, "DTV6 "); if (type & QAM) - printf("QAM "); + fprintf(fp, "QAM "); if (type & DTV7) - printf("DTV7 "); + fprintf(fp, "DTV7 "); if (type & DTV78) - printf("DTV78 "); + fprintf(fp, "DTV78 "); if (type & DTV8) - printf("DTV8 "); + fprintf(fp, "DTV8 "); if (type & FM) - printf("FM "); + fprintf(fp, "FM "); if (type & INPUT1) - printf("INPUT1 "); + fprintf(fp, "INPUT1 "); if (type & LCD) - printf("LCD "); + fprintf(fp, "LCD "); if (type & NOGD) - printf("NOGD "); + fprintf(fp, "NOGD "); if (type & MONO) - printf("MONO "); + fprintf(fp, "MONO "); if (type & ATSC) - printf("ATSC "); + fprintf(fp, "ATSC "); if (type & IF) - printf("IF "); + fprintf(fp, "IF "); if (type & LG60) - printf("LG60 "); + fprintf(fp, "LG60 "); if (type & ATI638) - printf("ATI638 "); + fprintf(fp, "ATI638 "); if (type & OREN538) - printf("OREN538 "); + fprintf(fp, "OREN538 "); if (type & OREN36) - printf("OREN36 "); + fprintf(fp, "OREN36 "); if (type & TOYOTA388) - printf("TOYOTA388 "); + fprintf(fp, "TOYOTA388 "); if (type & TOYOTA794) - printf("TOYOTA794 "); + fprintf(fp, "TOYOTA794 "); if (type & DIBCOM52) - printf("DIBCOM52 "); + fprintf(fp, "DIBCOM52 "); if (type & ZARLINK456) - printf("ZARLINK456 "); + fprintf(fp, "ZARLINK456 "); if (type & CHINA) - printf("CHINA "); + fprintf(fp, "CHINA "); if (type & F6MHZ) - printf("F6MHZ "); + fprintf(fp, "F6MHZ "); if (type & INPUT2) - printf("INPUT2 "); + fprintf(fp, "INPUT2 "); if (type & HAS_IF) - printf("HAS IF "); + fprintf(fp, "HAS IF "); } -void dump_firm_std(v4l2_std_id id) +void dump_firm_std(FILE *fp, v4l2_std_id id) { v4l2_std_id old=-1, curr_id; @@ -362,127 +368,127 @@ void dump_firm_std(v4l2_std_id id) while (old!=id) { old=id; if ( (id & V4L2_STD_PAL) == V4L2_STD_PAL) { - printf ("PAL "); + fprintf (fp, "PAL "); curr_id = V4L2_STD_PAL; } else if ( (id & V4L2_STD_MN) == V4L2_STD_MN) { - printf ("NTSC PAL/M PAL/N "); + fprintf (fp, "NTSC PAL/M PAL/N "); curr_id = V4L2_STD_PAL; } else if ( (id & V4L2_STD_PAL_BG) == V4L2_STD_PAL_BG) { - printf ("PAL/BG "); + fprintf (fp, "PAL/BG "); curr_id = V4L2_STD_PAL_BG; } else if ( (id & V4L2_STD_PAL_DK) == V4L2_STD_PAL_DK) { - printf ("PAL/DK "); + fprintf (fp, "PAL/DK "); curr_id = V4L2_STD_PAL_DK; } else if ( (id & V4L2_STD_PAL_B) == V4L2_STD_PAL_B) { - printf ("PAL/B "); + fprintf (fp, "PAL/B "); curr_id = V4L2_STD_PAL_B; } else if ( (id & V4L2_STD_PAL_B1) == V4L2_STD_PAL_B1) { - printf ("PAL/B1 "); + fprintf (fp, "PAL/B1 "); curr_id = V4L2_STD_PAL_B1; } else if ( (id & V4L2_STD_PAL_G) == V4L2_STD_PAL_G) { - printf ("PAL/G "); + fprintf (fp, "PAL/G "); curr_id = V4L2_STD_PAL_G; } else if ( (id & V4L2_STD_PAL_H) == V4L2_STD_PAL_H) { - printf ("PAL/H "); + fprintf (fp, "PAL/H "); curr_id = V4L2_STD_PAL_H; } else if ( (id & V4L2_STD_PAL_I) == V4L2_STD_PAL_I) { - printf ("PAL/I "); + fprintf (fp, "PAL/I "); curr_id = V4L2_STD_PAL_I; } else if ( (id & V4L2_STD_PAL_D) == V4L2_STD_PAL_D) { - printf ("PAL/D "); + fprintf (fp, "PAL/D "); curr_id = V4L2_STD_PAL_D; } else if ( (id & V4L2_STD_PAL_D1) == V4L2_STD_PAL_D1) { - printf ("PAL/D1 "); + fprintf (fp, "PAL/D1 "); curr_id = V4L2_STD_PAL_D1; } else if ( (id & V4L2_STD_PAL_K) == V4L2_STD_PAL_K) { - printf ("PAL/K "); + fprintf (fp, "PAL/K "); curr_id = V4L2_STD_PAL_K; } else if ( (id & V4L2_STD_PAL_M) == V4L2_STD_PAL_M) { - printf ("PAL/M "); + fprintf (fp, "PAL/M "); curr_id = V4L2_STD_PAL_M; } else if ( (id & V4L2_STD_PAL_N) == V4L2_STD_PAL_N) { - printf ("PAL/N "); + fprintf (fp, "PAL/N "); curr_id = V4L2_STD_PAL_N; } else if ( (id & V4L2_STD_PAL_Nc) == V4L2_STD_PAL_Nc) { - printf ("PAL/Nc "); + fprintf (fp, "PAL/Nc "); curr_id = V4L2_STD_PAL_Nc; } else if ( (id & V4L2_STD_PAL_60) == V4L2_STD_PAL_60) { - printf ("PAL/60 "); + fprintf (fp, "PAL/60 "); curr_id = V4L2_STD_PAL_60; } else if ( (id & V4L2_STD_NTSC) == V4L2_STD_NTSC) { - printf ("NTSC "); + fprintf (fp, "NTSC "); curr_id = V4L2_STD_NTSC; } else if ( (id & V4L2_STD_NTSC_M) == V4L2_STD_NTSC_M) { - printf ("NTSC/M "); + fprintf (fp, "NTSC/M "); curr_id = V4L2_STD_NTSC_M; } else if ( (id & V4L2_STD_NTSC_M_JP) == V4L2_STD_NTSC_M_JP) { - printf ("NTSC/M Jp "); + fprintf (fp, "NTSC/M Jp "); curr_id = V4L2_STD_NTSC_M_JP; } else if ( (id & V4L2_STD_NTSC_443) == V4L2_STD_NTSC_443) { - printf ("NTSC 443 "); + fprintf (fp, "NTSC 443 "); curr_id = V4L2_STD_NTSC_443; } else if ( (id & V4L2_STD_NTSC_M_KR) == V4L2_STD_NTSC_M_KR) { - printf ("NTSC/M Kr "); + fprintf (fp, "NTSC/M Kr "); curr_id = V4L2_STD_NTSC_M_KR; } else if ( (id & V4L2_STD_SECAM) == V4L2_STD_SECAM) { - printf ("SECAM "); + fprintf (fp, "SECAM "); curr_id = V4L2_STD_SECAM; } else if ( (id & V4L2_STD_SECAM_DK) == V4L2_STD_SECAM_DK) { - printf ("SECAM/DK "); + fprintf (fp, "SECAM/DK "); curr_id = V4L2_STD_SECAM_DK; } else if ( (id & V4L2_STD_SECAM_B) == V4L2_STD_SECAM_B) { - printf ("SECAM/B "); + fprintf (fp, "SECAM/B "); curr_id = V4L2_STD_SECAM_B; } else if ( (id & V4L2_STD_SECAM_D) == V4L2_STD_SECAM_D) { - printf ("SECAM/D "); + fprintf (fp, "SECAM/D "); curr_id = V4L2_STD_SECAM_D; } else if ( (id & V4L2_STD_SECAM_G) == V4L2_STD_SECAM_G) { - printf ("SECAM/G "); + fprintf (fp, "SECAM/G "); curr_id = V4L2_STD_SECAM_G; } else if ( (id & V4L2_STD_SECAM_H) == V4L2_STD_SECAM_H) { - printf ("SECAM/H "); + fprintf (fp, "SECAM/H "); curr_id = V4L2_STD_SECAM_H; } else if ( (id & V4L2_STD_SECAM_K) == V4L2_STD_SECAM_K) { - printf ("SECAM/K "); + fprintf (fp, "SECAM/K "); curr_id = V4L2_STD_SECAM_K; } else if ( (id & V4L2_STD_SECAM_K1) == V4L2_STD_SECAM_K1) { - printf ("SECAM/K1 "); + fprintf (fp, "SECAM/K1 "); curr_id = V4L2_STD_SECAM_K1; } else if ( (id & V4L2_STD_SECAM_K3) == V4L2_STD_SECAM_K3) { - printf ("SECAM/K3 "); + fprintf (fp, "SECAM/K3 "); curr_id = V4L2_STD_SECAM_K3; } else if ( (id & V4L2_STD_SECAM_L) == V4L2_STD_SECAM_L) { - printf ("SECAM/L "); + fprintf (fp, "SECAM/L "); curr_id = V4L2_STD_SECAM_L; } else if ( (id & V4L2_STD_SECAM_LC) == V4L2_STD_SECAM_LC) { - printf ("SECAM/Lc "); + fprintf (fp, "SECAM/Lc "); curr_id = V4L2_STD_SECAM_LC; } else if ( (id & V4L2_STD_A2) == V4L2_STD_A2) { - printf ("A2 "); + fprintf (fp, "A2 "); curr_id = V4L2_STD_A2; } else if ( (id & V4L2_STD_A2_A) == V4L2_STD_A2_A) { - printf ("A2/A "); + fprintf (fp, "A2/A "); curr_id = V4L2_STD_A2_A; } else if ( (id & V4L2_STD_A2_B) == V4L2_STD_A2_B) { - printf ("A2/B "); + fprintf (fp, "A2/B "); curr_id = V4L2_STD_A2_B; } else if ( (id & V4L2_STD_NICAM) == V4L2_STD_NICAM) { - printf ("NICAM "); + fprintf (fp, "NICAM "); curr_id = V4L2_STD_NICAM; } else if ( (id & V4L2_STD_NICAM_A) == V4L2_STD_NICAM_A) { - printf ("NICAM/A "); + fprintf (fp, "NICAM/A "); curr_id = V4L2_STD_NICAM_A; } else if ( (id & V4L2_STD_NICAM_B) == V4L2_STD_NICAM_B) { - printf ("NICAM/B "); + fprintf (fp, "NICAM/B "); curr_id = V4L2_STD_NICAM_B; } else if ( (id & V4L2_STD_AM) == V4L2_STD_AM) { - printf ("AM "); + fprintf (fp, "AM "); curr_id = V4L2_STD_AM; } else if ( (id & V4L2_STD_BTSC) == V4L2_STD_BTSC) { - printf ("BTSC "); + fprintf (fp, "BTSC "); curr_id = V4L2_STD_BTSC; } else if ( (id & V4L2_STD_EIAJ) == V4L2_STD_EIAJ) { - printf ("EIAJ "); + fprintf (fp, "EIAJ "); curr_id = V4L2_STD_EIAJ; } else { curr_id = 0; @@ -492,6 +498,19 @@ void dump_firm_std(v4l2_std_id id) } } +void list_firmware_desc(FILE *fp, struct firmware_description *desc) +{ + fprintf(fp, "type: "); + dump_firm_type(fp, desc->type); + fprintf(fp, "(0x%08x), ", desc->type); + if (desc->type & HAS_IF) + fprintf(fp, "IF = %.2f MHz ", desc->int_freq/1000.0); + fprintf(fp, "id: "); + dump_firm_std(fp, desc->id); + fprintf(fp, "(%016llx), ", desc->id); + fprintf(fp, "size: %u\n", desc->size); +} + void list_firmware(struct firmware *f) { unsigned int i = 0; @@ -501,15 +520,7 @@ void list_firmware(struct firmware *f) { printf("standards:\t%u\n", f->nr_desc); for(i = 0; i < f->nr_desc; ++i) { printf("Firmware %2u, ", i); - printf("type: "); - dump_firm_type(f->desc[i].type); - printf("(0x%08x), ", f->desc[i].type); - if (f->desc[i].type & HAS_IF) - printf("IF = %.2f MHz ", f->desc[i].int_freq/1000.0); - printf("id: "); - dump_firm_std(f->desc[i].id); - printf("(%016llx), ", f->desc[i].id); - printf("size: %u\n", f->desc[i].size); + list_firmware_desc(stdout, &f->desc[i]); } } @@ -552,6 +563,285 @@ void set_standard_id(struct firmware* f, char* firmware_file, __u16 i, __u32 id) write_firmware_file(firmware_file, f); } +struct chunk_hunk; + +struct chunk_hunk { + unsigned char *data; + long pos; + int size; + int need_fix_endian; + struct chunk_hunk *next; +}; + +int seek_chunks(struct chunk_hunk *hunk, + unsigned char *seek, unsigned char *endp, /* File to seek */ + unsigned char *fdata, unsigned char *endf) /* Firmware */ +{ + unsigned char *fpos, *p, *p2, *lastp; + int rc, fsize; + unsigned char *temp_data; + + /* Method 1a: Seek for a complete firmware */ + for (p = seek; p < endp; p++) { + fpos = p; + for (p2 = fdata; p2 < endf; p2++, fpos++) { + if (*fpos != *p2) + break; + } + if (p2 == endf) { + hunk->data = NULL; + hunk->pos = p - seek; + hunk->size = endf - fdata; + hunk->next = NULL; + hunk->need_fix_endian = 0; + + return 1; + } + } + + fsize = endf - fdata; + temp_data = malloc(fsize); + memcpy(temp_data, fdata, fsize); + + /* Try again, changing endian */ + for (p2 = temp_data; p2 < temp_data + fsize;) { + unsigned char c; + int size = *p2 + (*(p2 + 1) << 8); + c = *p2; + *p2 = *(p2 + 1); + *(p2 + 1) = c; + p2+=2; + if ((size > 0) && (size < 0x8000)) + p2 += size; + } + + /* Method 1b: Seek for a complete firmware with changed endians */ + for (p = seek; p < endp; p++) { + fpos = p; + for (p2 = temp_data; p2 < temp_data + fsize; p2++, fpos++) { + if (*fpos != *p2) + break; + } + if (p2 == temp_data + fsize) { + hunk->data = NULL; + hunk->pos = p - seek; + hunk->size = endf - fdata; + hunk->next = NULL; + hunk->need_fix_endian = 1; + return 1; + } + } + + free(temp_data); + + /* Method 2: Seek for each firmware chunk */ + p = seek; + for (p2 = fdata; p2 < endf;) { + int size = *p2 + (*(p2 + 1) << 8); + + /* Encode size/reset/sleep directly */ + hunk->size = 2; + hunk->data = malloc(hunk->size); + memcpy(hunk->data, p2, hunk->size); + hunk->pos = -1; + hunk->next = calloc(1, sizeof(hunk)); + hunk->need_fix_endian = 0; + hunk = hunk->next; + p2 += 2; + + if ((size > 0) && (size < 0x8000)) { + unsigned char *ep; + int found = 0; + ep = p2 + size; + /////////////////// + for (; p < endp; p++) { + unsigned char *p3; + fpos = p; + for (p3 = p2; p3 < ep; p3++, fpos++) + if (*fpos != *p3) + break; + if (p3 == ep) { + found = 1; + hunk->pos = p - seek; + hunk->size = size; + hunk->next = calloc(1, sizeof(hunk)); + hunk->need_fix_endian = 0; + hunk = hunk->next; + + break; + } + } + if (!found) { + goto not_found; + } + p2 += size; + } + } + + return 2; + +not_found: + printf("Couldn't find firmware\n"); +return 0; + + /* Method 3: Seek for first firmware chunks */ +#if 0 +seek_next: + for (p = seek; p < endp; p++) { + fpos = p; + for (p2 = fdata; p2 < endf; p2++, fpos++) { + if (*fpos != *p2) + break; + } + if (p2 > fdata + 2) { + int i = 0; + printf("Found %ld equal bytes at %ld:\n", + p2 - fdata, p - seek); + fpos = p; + lastp = fpos; + for (p2 = fdata; p2 < endf; p2++, fpos++) { + if (*fpos != *p2) + break; + printf("%02x ",*p2); + } + for (i=0; p2 < endf && i <5 ; p2++, fpos++, i++) { + printf("%02x(%02x) ",*p2 , *fpos); + } + printf("\n"); + /* Seek for the next chunk */ + fdata = p2; + + if (fdata == endf) { + printf ("Found all chunks.\n"); + return 1; + } + } + } + + printf ("NOT FOUND: %02x\n", *fdata); + fdata++; + goto seek_next; +#endif +} + +void seek_firmware(struct firmware *f, char *seek_file, char *write_file) { + unsigned int i = 0, nfound = 0; + long size, rd = 0; + unsigned char *seek, *p, *endp, *p2, *endp2, *fpos; + /*FIXME: Calculate it, instead of using a hardcode value */ + char *md5 = "0e44dbf63bb0169d57446aec21881ff2"; + FILE *fp; + + struct chunk_hunk hunks[f->nr_desc]; + memset (hunks, 0, sizeof(hunks)); + + fp=fopen(seek_file, "r"); + if (!fp) { + perror("Opening seek file"); + exit(-1); + } + fseek(fp, 0L, SEEK_END); + size = ftell(fp); + rewind(fp); + seek = malloc(size); + p = seek; + + do { + i = fread(p, 1, 16768, fp); + if (i > 0) { + rd += i; + p += i; + } + } while (i > 0); + + fclose(fp); + + if (rd != size) { + fprintf(stderr, "Error while reading the seek file: " + "should read %ld, instead of %ld ", size, rd); + exit (-1); + } + endp = p; + + printf("firmware name:\t%s\n", f->name); + printf("version:\t%d.%d (%u)\n", f->version >> 8, f->version & 0xff, + f->version); + printf("number of standards:\t%u\n", f->nr_desc); + for(i = 0; i < f->nr_desc; ++i) { + int found; + + endp2 = f->desc[i].data + f->desc[i].size; + + found = seek_chunks (&hunks[i], + seek, endp, f->desc[i].data, endp2); + + if (!found) { + printf("NOT FOUND: Firmware %d ", i); + list_firmware_desc(stdout, &f->desc[i]); + } else { + nfound++; + printf("Found with method %d: Firmware %d ", found, i); + list_firmware_desc(stdout, &f->desc[i]); + } + } + printf ("Found %d complete firmwares\n", nfound); + + if (!write_file) + return; + + fp = fopen(write_file, "w"); + if (!fp) { + perror("Writing firmware file"); + exit(-1); + } + + fprintf(fp, "%s", extract_header); + for (i = 0; i < f->nr_desc; ++i) { + struct chunk_hunk *hunk = &hunks[i]; + + fprintf(fp, "\n\t#\n\t# Firmware %d, ", i); + list_firmware_desc(fp, &f->desc[i]); + fprintf(fp, "\t#\n\n"); + + fprintf(fp, "\twrite_le32(0x%08x);\t\t\t# Type\n", + f->desc[i].type); + fprintf(fp, "\twrite_le64(0x%08Lx, 0x%08Lx);\t# ID\n", + f->desc[i].id>>32, f->desc[i].id & 0xffffffff); + if (f->desc[i].type & HAS_IF) + fprintf(fp, "\twrite_le16(%d);\t\t\t# IF\n", + f->desc[i].int_freq); + fprintf(fp, "\twrite_le32(%d);\t\t\t# Size\n", + f->desc[i].size); + + while (hunk) { + if (hunk->data) { + int j; + fprintf(fp, "\tsyswrite(OUTFILE, "); + for (j = 0; j < hunk->size; j++) { + fprintf(fp, "chr(%d)", hunk->data[j]); + if (j < hunk->size-1) + fprintf(fp,"."); + } + fprintf(fp,");\n"); + } else { + if (!hunk->size) + break; + + if (hunk->need_fix_endian) + fprintf(fp, write_hunk_fix_endian, + hunk->pos, hunk->size); + else + fprintf(fp, write_hunk, + hunk->pos, hunk->size); + } + hunk = hunk->next; + } + } + + fprintf(fp, end_extract, seek_file, md5, "xc3028-v27.fw", + f->name, f->version, f->nr_desc); +} + void print_usage(void) { printf("firmware-tool usage:\n"); @@ -560,6 +850,7 @@ void print_usage(void) printf("\t firmware-tool --delete <index> <firmware-file>\n"); printf("\t firmware-tool --type <type> --index <i> <firmware-file>\n"); printf("\t firmware-tool --id <type> --index <i> <firmware-file>\n"); + printf("\t firmware-tool --seek <seek-file> [--write <write-file>] <firmware-file>\n"); } int main(int argc, char* argv[]) @@ -568,6 +859,7 @@ int main(int argc, char* argv[]) int nr_args; unsigned int action = 0; char* firmware_file, *file = NULL, *nr_str = NULL, *index_str = NULL; + char *seek_file = NULL, *write_file = NULL; struct firmware *f; __u64 nr; @@ -579,6 +871,8 @@ int main(int argc, char* argv[]) {"type", required_argument, 0, 't'}, {"id", required_argument, 0, 's'}, {"index", required_argument, 0, 'i'}, + {"seek", required_argument, 0, 'k'}, + {"write", required_argument , 0, 'w'}, {0, 0, 0, 0} }; int option_index = 0; @@ -632,6 +926,14 @@ int main(int argc, char* argv[]) case 'i': index_str = optarg; break; + case 'k': + puts("seek firmwares\n"); + action = SEEK_FIRM_ACTION; + seek_file = optarg; + break; + case 'w': + write_file = optarg; + break; default: print_usage(); return 0; @@ -680,6 +982,9 @@ int main(int argc, char* argv[]) case SET_ID_ACTION: set_standard_id(f, firmware_file, strtoul(index_str, NULL, 10), strtoul(nr_str, NULL, 10)); + + case SEEK_FIRM_ACTION: + seek_firmware(f, seek_file, write_file); break; } return 0; |