From b147ad1360afb6524fb2639d6cf5e5f1e151675b Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 31 Dec 2007 10:16:14 -0200 Subject: Add a tool to generate firmware extracting scripts for xc3028 From: Mauro Carvalho Chehab This is the tool used to generate extract_xc3028.pl. Once you have a firmware file, generated from other methods, like usb dumps, this tool allows to seek the firmware inside a windows driver, creating an extrating script. There are two methods to seek for a firmware: 1) a complete firmware seek; 2) seek for firmware hunks. For each firmware segment, it writes the segment size, and seeks for the segment inside the firmware. The result of method 2) is not optimized. In the case of hvr12x0 driver, the base firmwares didn't hit method (1), so, the extracting tool broke it into several small segments. This is not optimized, but works. Signed-off-by: Mauro Carvalho Chehab --- v4l2-apps/util/xc3028-firmware/extract_head.h | 161 +++++++++ v4l2-apps/util/xc3028-firmware/firmware-tool.c | 467 ++++++++++++++++++++----- 2 files changed, 545 insertions(+), 83 deletions(-) create mode 100644 v4l2-apps/util/xc3028-firmware/extract_head.h (limited to 'v4l2-apps/util') diff --git a/v4l2-apps/util/xc3028-firmware/extract_head.h b/v4l2-apps/util/xc3028-firmware/extract_head.h new file mode 100644 index 000000000..9ca83377b --- /dev/null +++ b/v4l2-apps/util/xc3028-firmware/extract_head.h @@ -0,0 +1,161 @@ +char *extract_header = "#!/usr/bin/perl\n" + "#use strict;\n" + "use IO::Handle;\n" + "\n" + "my $debug=0;\n" + "\n" + "sub verify ($$)\n" + "{\n" + " my ($filename, $hash) = @_;\n" + " my ($testhash);\n" + "\n" + " if (system(\"which md5sum > /dev/null 2>&1\")) {\n" + " die \"This firmware requires the md5sum command - see http://www.gnu.org/software/coreutils/\\n\";\n" + " }\n" + "\n" + " open(CMD, \"md5sum \".$filename.\"|\");\n" + " $testhash = ;\n" + " $testhash =~ /([a-zA-Z0-9]*)/;\n" + " $testhash = $1;\n" + " close CMD;\n" + " die \"Hash of extracted file does not match (found $testhash, expected $hash!\\n\" if ($testhash ne $hash);\n" + "}\n" + "\n" + "sub get_hunk ($$)\n" + "{\n" + " my ($offset, $length) = @_;\n" + " my ($chunklength, $buf, $rcount, $out);\n" + "\n" + " sysseek(INFILE, $offset, SEEK_SET);\n" + " while ($length > 0) {\n" + " # Calc chunk size\n" + " $chunklength = 2048;\n" + " $chunklength = $length if ($chunklength > $length);\n" + "\n" + " $rcount = sysread(INFILE, $buf, $chunklength);\n" + " die \"Ran out of data\\n\" if ($rcount != $chunklength);\n" + " $out .= $buf;\n" + " $length -= $rcount;\n" + " }\n" + " return $out;\n" + "}\n" + "\n" + "sub write_le16($)\n" + "{\n" + " my $val = shift;\n" + " my $msb = ($val >> 8) &0xff;\n" + " my $lsb = $val & 0xff;\n" + "\n" + " syswrite(OUTFILE, chr($lsb).chr($msb));\n" + "}\n" + "\n" + "sub write_le32($)\n" + "{\n" + " my $val = shift;\n" + " my $l3 = ($val >> 24) & 0xff;\n" + " my $l2 = ($val >> 16) & 0xff;\n" + " my $l1 = ($val >> 8) & 0xff;\n" + " my $l0 = $val & 0xff;\n" + "\n" + " syswrite(OUTFILE, chr($l0).chr($l1).chr($l2).chr($l3));\n" + "}\n" + "\n" + "sub write_le64($)\n" + "{\n" + " my $val = shift;\n" + " my $l7 = ($val >> 56) & 0xff;\n" + " my $l6 = ($val >> 48) & 0xff;\n" + " my $l5 = ($val >> 40) & 0xff;\n" + " my $l4 = ($val >> 32) & 0xff;\n" + " my $l3 = ($val >> 24) & 0xff;\n" + " my $l2 = ($val >> 16) & 0xff;\n" + " my $l1 = ($val >> 8) & 0xff;\n" + " my $l0 = $val & 0xff;\n" + "\n" + " syswrite(OUTFILE,\n" + " chr($l0).chr($l1).chr($l2).chr($l3).\n" + " chr($l4).chr($l5).chr($l6).chr($l7));\n" + "}\n" + "\n" + "sub write_hunk($$)\n" + "{\n" + " my ($offset, $length) = @_;\n" + " my $out = get_hunk($offset, $length);\n" + "\n" + " printf \"(len %d) \",$length if ($debug);\n" +// " write_le16($length);\n" + "\n" + " for (my $i=0;$i<$length;$i++) {\n" + " printf \"%02x \",ord(substr($out,$i,1)) if ($debug);\n" + " }\n" + " printf \"\\n\" if ($debug);\n" + "\n" + " syswrite(OUTFILE, $out);\n" + "}\n" + "\n" + "sub write_hunk_fix_endian($$)\n" + "{\n" + " my ($offset, $length) = @_;\n" + " my $out = get_hunk($offset, $length);\n" + "\n" + " printf \"(len_fix %d) \",$length if ($debug);\n" +//"syswrite(OUTFILE, \"0123456789ABCDEF\");\n" +// " write_le16($length);\n" + "\n" + " for (my $i=0;$i<$length;$i++) {\n" + " printf \"%02x \",ord(substr($out,$i,1)) if ($debug);\n" + " }\n" + " printf \"\\n\" if ($debug);\n" + "\n" + " $i=0;\n" + " while ($i<$length) {\n" + " my $size = ord(substr($out,$i,1))*256+ord(substr($out,$i+1,1));\n" + " syswrite(OUTFILE, substr($out,$i+1,1));\n" + " syswrite(OUTFILE, substr($out,$i,1));\n" + " $i+=2;\n" + " for (my $j=0;$j<$size;$j++) {\n" + " syswrite(OUTFILE, substr($out,$j+$i,1));\n" + " }\n" + " $i+=$size;\n" + " }\n" + "}\n" + "\n" + "sub main_firmware($$$$)\n" + "{\n" + " my $out;\n" + " my $j=0;\n" + " my $outfile = shift;\n" + " my $name = shift;\n" + " my $version = shift;\n" + " my $nr_desc = shift;\n" + "\n" + " for ($j = length($name); $j <32; $j++) {\n" + " $name = $name.chr(0);\n" + "}\n\n" + " open OUTFILE, \">$outfile\";\n" + " syswrite(OUTFILE, $name);\n" + " write_le16($version);\n" + " write_le16($nr_desc);\n"; + +char *write_hunk = "\twrite_hunk(%d, %d);\n"; +char *write_hunk_fix_endian = "\twrite_hunk_fix_endian(%d, %d);\n"; + +// Parameters: file windows filename, hash, outfile, version, name +char *end_extract = "}\n\nsub extract_firmware {\n" + " my $sourcefile = \"%s\";\n" + " my $hash = \"%s\";\n" + " my $outfile = \"%s\";\n" + " my $name = \"%s\";\n" + " my $version = %d;\n" + " my $nr_desc = %d;\n" + " my $out;\n" + "\n" + " verify($sourcefile, $hash);\n" + "\n" + " open INFILE, \"<$sourcefile\";\n" + " main_firmware($outfile, $name, $version, $nr_desc);\n" + " close INFILE;\n" + "}\n" + "\n" + "extract_firmware;\n" + "printf \"Firmwares generated.\\n\";\n"; diff --git a/v4l2-apps/util/xc3028-firmware/firmware-tool.c b/v4l2-apps/util/xc3028-firmware/firmware-tool.c index a8e6d0c01..c0003ddff 100644 --- a/v4l2-apps/util/xc3028-firmware/firmware-tool.c +++ b/v4l2-apps/util/xc3028-firmware/firmware-tool.c @@ -31,6 +31,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 +39,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 +289,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 +364,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 +494,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 +516,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 +559,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) { + printf("Firmware found at %ld\n", p - seek); + 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; p2++) { + int size = *p2 + (*(p2 + 1) << 8); + if ((size > 0) && (size < 0x8000)) { + unsigned char c = *p2; + *p2 = *(p2 + 1); + *(p2 + 1) = c; + p2 += size + 1; + + } + } + + /* 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) { + printf("Firmware found at %ld (fix_endian)\n", + p - seek); + 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; + printf("Firmware hunk found at %ld \n", + p - seek); + + break; + } + } + if (!found) { + goto not_found; + } + p2 += size; + } + } + + printf ("Firmware found by using method 3\n"); + return 1; + +not_found: + printf("method 2 couldn't find firmware\n"); +return 0; + + /* Method 3: Seek for first firmware chunks */ + +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; +} + +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("Firmware %d Not found: ", i); + list_firmware_desc(stdout, &f->desc[i]); + } + + nfound += found; + } + 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(%d);\n", f->desc[i].type); + fprintf(fp, "\twrite_le64(%Ld);\n", f->desc[i].id); + if (f->desc[i].type & HAS_IF) + fprintf(fp, "\twrite_le16(%d);\n", + f->desc[i].int_freq); + fprintf(fp, "\twrite_le32(%d);\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 +846,7 @@ void print_usage(void) printf("\t firmware-tool --delete \n"); printf("\t firmware-tool --type --index \n"); printf("\t firmware-tool --id --index \n"); + printf("\t firmware-tool --seek [--write ] \n"); } int main(int argc, char* argv[]) @@ -568,6 +855,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 +867,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 +922,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 +978,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; -- cgit v1.2.3 From da37b1fc270b1ec30e5b91f3d669d6b2162fa935 Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Mon, 31 Dec 2007 11:12:50 -0200 Subject: Improve method 1 From: Mauro Carvalho Chehab Xceive firmwares seem to use Big Endian for encoding size, delay and reset. Kernel drivers uses Little Endian. Before this patch, method 1 were fixing endian only for size. This patch changes the behavior to change endian also for delay and reset. With this change, with HVR12x0 file, method (1) works for all firmwares. This produces a very optimized script. The seek method is known to work with firmwares version 2.7 and 2.5. However, drivers with firmware version 1.x have a different internal format. So, another seek method will be required to allow the script to work on those firmwares. Signed-off-by: Mauro Carvalho Chehab --- v4l2-apps/util/xc3028-firmware/extract_head.h | 11 ++++---- v4l2-apps/util/xc3028-firmware/firmware-tool.c | 37 ++++++++++++-------------- 2 files changed, 22 insertions(+), 26 deletions(-) (limited to 'v4l2-apps/util') diff --git a/v4l2-apps/util/xc3028-firmware/extract_head.h b/v4l2-apps/util/xc3028-firmware/extract_head.h index 9ca83377b..0bc0d19f9 100644 --- a/v4l2-apps/util/xc3028-firmware/extract_head.h +++ b/v4l2-apps/util/xc3028-firmware/extract_head.h @@ -83,7 +83,6 @@ char *extract_header = "#!/usr/bin/perl\n" " my $out = get_hunk($offset, $length);\n" "\n" " printf \"(len %d) \",$length if ($debug);\n" -// " write_le16($length);\n" "\n" " for (my $i=0;$i<$length;$i++) {\n" " printf \"%02x \",ord(substr($out,$i,1)) if ($debug);\n" @@ -99,8 +98,6 @@ char *extract_header = "#!/usr/bin/perl\n" " my $out = get_hunk($offset, $length);\n" "\n" " printf \"(len_fix %d) \",$length if ($debug);\n" -//"syswrite(OUTFILE, \"0123456789ABCDEF\");\n" -// " write_le16($length);\n" "\n" " for (my $i=0;$i<$length;$i++) {\n" " printf \"%02x \",ord(substr($out,$i,1)) if ($debug);\n" @@ -113,10 +110,12 @@ char *extract_header = "#!/usr/bin/perl\n" " syswrite(OUTFILE, substr($out,$i+1,1));\n" " syswrite(OUTFILE, substr($out,$i,1));\n" " $i+=2;\n" - " for (my $j=0;$j<$size;$j++) {\n" - " syswrite(OUTFILE, substr($out,$j+$i,1));\n" + " if ($size>0 && $size <0x8000) {\n" + " for (my $j=0;$j<$size;$j++) {\n" + " syswrite(OUTFILE, substr($out,$j+$i,1));\n" + " }\n" + " $i+=$size;\n" " }\n" - " $i+=$size;\n" " }\n" "}\n" "\n" diff --git a/v4l2-apps/util/xc3028-firmware/firmware-tool.c b/v4l2-apps/util/xc3028-firmware/firmware-tool.c index c0003ddff..b48495aa4 100644 --- a/v4l2-apps/util/xc3028-firmware/firmware-tool.c +++ b/v4l2-apps/util/xc3028-firmware/firmware-tool.c @@ -585,7 +585,6 @@ int seek_chunks(struct chunk_hunk *hunk, break; } if (p2 == endf) { - printf("Firmware found at %ld\n", p - seek); hunk->data = NULL; hunk->pos = p - seek; hunk->size = endf - fdata; @@ -601,15 +600,15 @@ int seek_chunks(struct chunk_hunk *hunk, memcpy(temp_data, fdata, fsize); /* Try again, changing endian */ - for (p2 = temp_data; p2 < temp_data + fsize; p2++) { + for (p2 = temp_data; p2 < temp_data + fsize;) { + unsigned char c; int size = *p2 + (*(p2 + 1) << 8); - if ((size > 0) && (size < 0x8000)) { - unsigned char c = *p2; - *p2 = *(p2 + 1); - *(p2 + 1) = c; - p2 += size + 1; - - } + 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 */ @@ -620,8 +619,6 @@ int seek_chunks(struct chunk_hunk *hunk, break; } if (p2 == temp_data + fsize) { - printf("Firmware found at %ld (fix_endian)\n", - p - seek); hunk->data = NULL; hunk->pos = p - seek; hunk->size = endf - fdata; @@ -666,8 +663,6 @@ int seek_chunks(struct chunk_hunk *hunk, hunk->next = calloc(1, sizeof(hunk)); hunk->need_fix_endian = 0; hunk = hunk->next; - printf("Firmware hunk found at %ld \n", - p - seek); break; } @@ -679,15 +674,14 @@ int seek_chunks(struct chunk_hunk *hunk, } } - printf ("Firmware found by using method 3\n"); - return 1; + return 2; not_found: - printf("method 2 couldn't find firmware\n"); + 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; @@ -723,6 +717,7 @@ seek_next: printf ("NOT FOUND: %02x\n", *fdata); fdata++; goto seek_next; +#endif } void seek_firmware(struct firmware *f, char *seek_file, char *write_file) { @@ -777,11 +772,13 @@ void seek_firmware(struct firmware *f, char *seek_file, char *write_file) { seek, endp, f->desc[i].data, endp2); if (!found) { - printf("Firmware %d Not found: ", i); + 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]); } - - nfound += found; } printf ("Found %d complete firmwares\n", nfound); -- cgit v1.2.3 From fd33d30eaf1d0c4f84d835172c845e7c4b15033e Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Tue, 1 Jan 2008 09:09:43 -0200 Subject: Avoid needing to run perl script on machines with 64-bit int From: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- v4l2-apps/util/xc3028-firmware/extract_head.h | 21 +++++++++++---------- v4l2-apps/util/xc3028-firmware/firmware-tool.c | 15 +++++++++++---- 2 files changed, 22 insertions(+), 14 deletions(-) (limited to 'v4l2-apps/util') diff --git a/v4l2-apps/util/xc3028-firmware/extract_head.h b/v4l2-apps/util/xc3028-firmware/extract_head.h index 0bc0d19f9..373ac78ba 100644 --- a/v4l2-apps/util/xc3028-firmware/extract_head.h +++ b/v4l2-apps/util/xc3028-firmware/extract_head.h @@ -60,17 +60,18 @@ char *extract_header = "#!/usr/bin/perl\n" " syswrite(OUTFILE, chr($l0).chr($l1).chr($l2).chr($l3));\n" "}\n" "\n" - "sub write_le64($)\n" + "sub write_le64($$)\n" "{\n" - " my $val = shift;\n" - " my $l7 = ($val >> 56) & 0xff;\n" - " my $l6 = ($val >> 48) & 0xff;\n" - " my $l5 = ($val >> 40) & 0xff;\n" - " my $l4 = ($val >> 32) & 0xff;\n" - " my $l3 = ($val >> 24) & 0xff;\n" - " my $l2 = ($val >> 16) & 0xff;\n" - " my $l1 = ($val >> 8) & 0xff;\n" - " my $l0 = $val & 0xff;\n" + " my $msb_val = shift;\n" + " my $lsb_val = shift;\n" + " my $l7 = ($msb_val >> 24) & 0xff;\n" + " my $l6 = ($msb_val >> 16) & 0xff;\n" + " my $l5 = ($msb_val >> 8) & 0xff;\n" + " my $l4 = $msb_val & 0xff;\n\n" + " my $l3 = ($lsb_val >> 24) & 0xff;\n" + " my $l2 = ($lsb_val >> 16) & 0xff;\n" + " my $l1 = ($lsb_val >> 8) & 0xff;\n" + " my $l0 = $lsb_val & 0xff;\n" "\n" " syswrite(OUTFILE,\n" " chr($l0).chr($l1).chr($l2).chr($l3).\n" diff --git a/v4l2-apps/util/xc3028-firmware/firmware-tool.c b/v4l2-apps/util/xc3028-firmware/firmware-tool.c index b48495aa4..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 + Copyright (C) 2007, 2008 Mauro Carvalho Chehab + - 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 @@ -799,12 +803,15 @@ void seek_firmware(struct firmware *f, char *seek_file, char *write_file) { list_firmware_desc(fp, &f->desc[i]); fprintf(fp, "\t#\n\n"); - fprintf(fp, "\twrite_le32(%d);\n", f->desc[i].type); - fprintf(fp, "\twrite_le64(%Ld);\n", f->desc[i].id); + 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);\n", + fprintf(fp, "\twrite_le16(%d);\t\t\t# IF\n", f->desc[i].int_freq); - fprintf(fp, "\twrite_le32(%d);\n", f->desc[i].size); + fprintf(fp, "\twrite_le32(%d);\t\t\t# Size\n", + f->desc[i].size); while (hunk) { if (hunk->data) { -- cgit v1.2.3 From 55da391ab67c98f9a35581a880ceadf1574b10da Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 2 Jan 2008 13:28:52 -0200 Subject: Show board id at general tab on qv4l2 From: Mauro Carvalho Chehab When you have several boards inside a machine, you need to know what board qv4l2 is using. This patch presents driver, board name and bus id, to help identifying the board. Signed-off-by: Mauro Carvalho Chehab --- v4l2-apps/util/qv4l2/general-tab.cpp | 22 ++++++++++++++++++++++ v4l2-apps/util/qv4l2/general-tab.h | 1 + 2 files changed, 23 insertions(+) (limited to 'v4l2-apps/util') diff --git a/v4l2-apps/util/qv4l2/general-tab.cpp b/v4l2-apps/util/qv4l2/general-tab.cpp index 93ab329ba..e00a968f7 100644 --- a/v4l2-apps/util/qv4l2/general-tab.cpp +++ b/v4l2-apps/util/qv4l2/general-tab.cpp @@ -39,6 +39,28 @@ GeneralTab::GeneralTab(int _fd, int n, QWidget *parent) : setSpacing(3); + memset(&querycap, 0, sizeof(querycap)); + if (ioctl(fd, VIDIOC_QUERYCAP, &querycap) >=0) { + QLabel *l1 = new QLabel("Driver:", this); + l1->setAlignment(Qt::AlignRight); + + QLabel *l1t = new QLabel((char *)querycap.driver, this); + + QLabel *l2 = new QLabel("Card: ", this); + l2->setAlignment(Qt::AlignRight); + + QLabel *l2t = new QLabel((char *)querycap.card, this); + + QLabel *l3 = new QLabel("Bus: ", this); + l3->setAlignment(Qt::AlignRight); + + QLabel *l3t = new QLabel((char *)querycap.bus_info, this); + + QLabel *l4 = new QLabel("", this); + QLabel *l4t = new QLabel("", this); + + } + memset(&tuner, 0, sizeof(tuner)); ioctl(fd, VIDIOC_G_TUNER, &tuner); if (tuner.rangehigh>INT_MAX) diff --git a/v4l2-apps/util/qv4l2/general-tab.h b/v4l2-apps/util/qv4l2/general-tab.h index 110632014..3612101e7 100644 --- a/v4l2-apps/util/qv4l2/general-tab.h +++ b/v4l2-apps/util/qv4l2/general-tab.h @@ -57,6 +57,7 @@ private: int fd; struct v4l2_tuner tuner; + struct v4l2_capability querycap; // General tab QComboBox *videoInput; -- cgit v1.2.3 From 51549372cf89b75379465e885cb3b2b178be53ad Mon Sep 17 00:00:00 2001 From: Mauro Carvalho Chehab Date: Wed, 2 Jan 2008 13:50:02 -0200 Subject: Adds device file name to General tab From: Mauro Carvalho Chehab Signed-off-by: Mauro Carvalho Chehab --- v4l2-apps/util/qv4l2/general-tab.cpp | 20 ++++++++++---------- v4l2-apps/util/qv4l2/general-tab.h | 2 +- v4l2-apps/util/qv4l2/qv4l2.cpp | 2 +- 3 files changed, 12 insertions(+), 12 deletions(-) (limited to 'v4l2-apps/util') diff --git a/v4l2-apps/util/qv4l2/general-tab.cpp b/v4l2-apps/util/qv4l2/general-tab.cpp index e00a968f7..d7f5a98d2 100644 --- a/v4l2-apps/util/qv4l2/general-tab.cpp +++ b/v4l2-apps/util/qv4l2/general-tab.cpp @@ -31,7 +31,7 @@ #include #include -GeneralTab::GeneralTab(int _fd, int n, QWidget *parent) : +GeneralTab::GeneralTab(const char *device, int _fd, int n, QWidget *parent) : QGrid(n, parent), fd(_fd) { @@ -41,24 +41,24 @@ GeneralTab::GeneralTab(int _fd, int n, QWidget *parent) : memset(&querycap, 0, sizeof(querycap)); if (ioctl(fd, VIDIOC_QUERYCAP, &querycap) >=0) { - QLabel *l1 = new QLabel("Driver:", this); + QLabel *l1 = new QLabel("Device:", this); + QLabel *l1t = new QLabel(device, this); l1->setAlignment(Qt::AlignRight); - QLabel *l1t = new QLabel((char *)querycap.driver, this); - - QLabel *l2 = new QLabel("Card: ", this); + QLabel *l2 = new QLabel("Driver:", this); l2->setAlignment(Qt::AlignRight); - QLabel *l2t = new QLabel((char *)querycap.card, this); + QLabel *l2t = new QLabel((char *)querycap.driver, this); - QLabel *l3 = new QLabel("Bus: ", this); + QLabel *l3 = new QLabel("Card:", this); l3->setAlignment(Qt::AlignRight); - QLabel *l3t = new QLabel((char *)querycap.bus_info, this); + QLabel *l3t = new QLabel((char *)querycap.card, this); - QLabel *l4 = new QLabel("", this); - QLabel *l4t = new QLabel("", this); + QLabel *l4 = new QLabel("Bus:", this); + l4->setAlignment(Qt::AlignRight); + QLabel *l4t = new QLabel((char *)querycap.bus_info, this); } memset(&tuner, 0, sizeof(tuner)); diff --git a/v4l2-apps/util/qv4l2/general-tab.h b/v4l2-apps/util/qv4l2/general-tab.h index 3612101e7..8130e11e1 100644 --- a/v4l2-apps/util/qv4l2/general-tab.h +++ b/v4l2-apps/util/qv4l2/general-tab.h @@ -33,7 +33,7 @@ class GeneralTab: public QGrid Q_OBJECT public: - GeneralTab(int fd, int n, QWidget *parent = 0); + GeneralTab(const char *device, int fd, int n, QWidget *parent = 0); virtual ~GeneralTab() {} private slots: diff --git a/v4l2-apps/util/qv4l2/qv4l2.cpp b/v4l2-apps/util/qv4l2/qv4l2.cpp index f9fb07e09..a93608af2 100644 --- a/v4l2-apps/util/qv4l2/qv4l2.cpp +++ b/v4l2-apps/util/qv4l2/qv4l2.cpp @@ -118,7 +118,7 @@ void ApplicationWindow::setDevice(const QString &device) fd = ::open(device, O_RDONLY); if (fd >= 0) { - tabs->addTab(new GeneralTab(fd, 4, tabs), "General"); + tabs->addTab(new GeneralTab(device, fd, 4, tabs), "General"); addTabs(); } if (QWidget *current = tabs->currentPage()) { -- cgit v1.2.3