summaryrefslogtreecommitdiff
path: root/v4l2-apps
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@infradead.org>2007-12-31 10:16:14 -0200
committerMauro Carvalho Chehab <mchehab@infradead.org>2007-12-31 10:16:14 -0200
commitb147ad1360afb6524fb2639d6cf5e5f1e151675b (patch)
tree704ce7af472fa1a97398393cb8f40fbe6fab3a24 /v4l2-apps
parente318344f562308e02e0221337dc1119c5729b1ef (diff)
downloadmediapointer-dvb-s2-b147ad1360afb6524fb2639d6cf5e5f1e151675b.tar.gz
mediapointer-dvb-s2-b147ad1360afb6524fb2639d6cf5e5f1e151675b.tar.bz2
Add a tool to generate firmware extracting scripts for xc3028
From: Mauro Carvalho Chehab <mchehab@infradead.org> 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 <mchehab@infradead.org>
Diffstat (limited to 'v4l2-apps')
-rw-r--r--v4l2-apps/util/xc3028-firmware/extract_head.h161
-rw-r--r--v4l2-apps/util/xc3028-firmware/firmware-tool.c467
2 files changed, 545 insertions, 83 deletions
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 = <CMD>;\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 <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 +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;