1#!/usr/bin/perl 2# DVB firmware extractor 3# 4# (c) 2004 Andrew de Quincey 5# 6# This program is free software; you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation; either version 2 of the License, or 9# (at your option) any later version. 10# 11# This program is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# 15# GNU General Public License for more details. 16# 17# You should have received a copy of the GNU General Public License 18# along with this program; if not, write to the Free Software 19# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 21use File::Temp qw/ tempdir /; 22use IO::Handle; 23 24@components = ( "sp8870", "sp887x", "tda10045", "tda10046", 25 "tda10046lifeview", "av7110", "dec2000t", "dec2540t", 26 "dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004", 27 "or51211", "or51132_qam", "or51132_vsb", "bluebird", 28 "opera1"); 29 30# Check args 31syntax() if (scalar(@ARGV) != 1); 32$cid = $ARGV[0]; 33 34# Do it! 35for ($i=0; $i < scalar(@components); $i++) { 36 if ($cid eq $components[$i]) { 37 $outfile = eval($cid); 38 die $@ if $@; 39 print STDERR <<EOF; 40Firmware $outfile extracted successfully. 41Now copy it to either /usr/lib/hotplug/firmware or /lib/firmware 42(depending on configuration of firmware hotplug). 43EOF 44 exit(0); 45 } 46} 47 48# If we get here, it wasn't found 49print STDERR "Unknown component \"$cid\"\n"; 50syntax(); 51 52 53 54 55# --------------------------------------------------------------- 56# Firmware-specific extraction subroutines 57 58sub sp8870 { 59 my $sourcefile = "tt_Premium_217g.zip"; 60 my $url = "http://www.softwarepatch.pl/9999ccd06a4813cb827dbb0005071c71/$sourcefile"; 61 my $hash = "53970ec17a538945a6d8cb608a7b3899"; 62 my $outfile = "dvb-fe-sp8870.fw"; 63 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 64 65 checkstandard(); 66 67 wgetfile($sourcefile, $url); 68 unzip($sourcefile, $tmpdir); 69 verify("$tmpdir/software/OEM/HE/App/boot/SC_MAIN.MC", $hash); 70 copy("$tmpdir/software/OEM/HE/App/boot/SC_MAIN.MC", $outfile); 71 72 $outfile; 73} 74 75sub sp887x { 76 my $sourcefile = "Dvbt1.3.57.6.zip"; 77 my $url = "http://www.avermedia.com/software/$sourcefile"; 78 my $cabfile = "DVBT Net Ver1.3.57.6/disk1/data1.cab"; 79 my $hash = "237938d53a7f834c05c42b894ca68ac3"; 80 my $outfile = "dvb-fe-sp887x.fw"; 81 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 82 83 checkstandard(); 84 checkunshield(); 85 86 wgetfile($sourcefile, $url); 87 unzip($sourcefile, $tmpdir); 88 unshield("$tmpdir/$cabfile", $tmpdir); 89 verify("$tmpdir/ZEnglish/sc_main.mc", $hash); 90 copy("$tmpdir/ZEnglish/sc_main.mc", $outfile); 91 92 $outfile; 93} 94 95sub tda10045 { 96 my $sourcefile = "tt_budget_217g.zip"; 97 my $url = "http://www.technotrend.de/new/217g/$sourcefile"; 98 my $hash = "2105fd5bf37842fbcdfa4bfd58f3594a"; 99 my $outfile = "dvb-fe-tda10045.fw"; 100 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 101 102 checkstandard(); 103 104 wgetfile($sourcefile, $url); 105 unzip($sourcefile, $tmpdir); 106 extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x37ef9, 30555, "$tmpdir/fwtmp"); 107 verify("$tmpdir/fwtmp", $hash); 108 copy("$tmpdir/fwtmp", $outfile); 109 110 $outfile; 111} 112 113sub tda10046 { 114 my $sourcefile = "TT_PCI_2.19h_28_11_2006.zip"; 115 my $url = "http://technotrend-online.com/download/software/219/$sourcefile"; 116 my $hash = "6a7e1e2f2644b162ff0502367553c72d"; 117 my $outfile = "dvb-fe-tda10046.fw"; 118 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 119 120 checkstandard(); 121 122 wgetfile($sourcefile, $url); 123 unzip($sourcefile, $tmpdir); 124 extract("$tmpdir/TT_PCI_2.19h_28_11_2006/software/OEM/PCI/App/ttlcdacc.dll", 0x65389, 24478, "$tmpdir/fwtmp"); 125 verify("$tmpdir/fwtmp", $hash); 126 copy("$tmpdir/fwtmp", $outfile); 127 128 $outfile; 129} 130 131sub tda10046lifeview { 132 my $sourcefile = "Drv_2.11.02.zip"; 133 my $url = "http://www.lifeview.com.tw/drivers/pci_card/FlyDVB-T/$sourcefile"; 134 my $hash = "1ea24dee4eea8fe971686981f34fd2e0"; 135 my $outfile = "dvb-fe-tda10046.fw"; 136 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 137 138 checkstandard(); 139 140 wgetfile($sourcefile, $url); 141 unzip($sourcefile, $tmpdir); 142 extract("$tmpdir/LVHybrid.sys", 0x8b088, 24602, "$tmpdir/fwtmp"); 143 verify("$tmpdir/fwtmp", $hash); 144 copy("$tmpdir/fwtmp", $outfile); 145 146 $outfile; 147} 148 149sub av7110 { 150 my $sourcefile = "dvb-ttpci-01.fw-261d"; 151 my $url = "http://www.linuxtv.org/downloads/firmware/$sourcefile"; 152 my $hash = "603431b6259715a8e88f376a53b64e2f"; 153 my $outfile = "dvb-ttpci-01.fw"; 154 155 checkstandard(); 156 157 wgetfile($sourcefile, $url); 158 verify($sourcefile, $hash); 159 copy($sourcefile, $outfile); 160 161 $outfile; 162} 163 164sub dec2000t { 165 my $sourcefile = "dec217g.exe"; 166 my $url = "http://hauppauge.lightpath.net/de/$sourcefile"; 167 my $hash = "bd86f458cee4a8f0a8ce2d20c66215a9"; 168 my $outfile = "dvb-ttusb-dec-2000t.fw"; 169 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 170 171 checkstandard(); 172 173 wgetfile($sourcefile, $url); 174 unzip($sourcefile, $tmpdir); 175 verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_T.bin", $hash); 176 copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_T.bin", $outfile); 177 178 $outfile; 179} 180 181sub dec2540t { 182 my $sourcefile = "dec217g.exe"; 183 my $url = "http://hauppauge.lightpath.net/de/$sourcefile"; 184 my $hash = "53e58f4f5b5c2930beee74a7681fed92"; 185 my $outfile = "dvb-ttusb-dec-2540t.fw"; 186 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 187 188 checkstandard(); 189 190 wgetfile($sourcefile, $url); 191 unzip($sourcefile, $tmpdir); 192 verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_X.bin", $hash); 193 copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_X.bin", $outfile); 194 195 $outfile; 196} 197 198sub dec3000s { 199 my $sourcefile = "dec217g.exe"; 200 my $url = "http://hauppauge.lightpath.net/de/$sourcefile"; 201 my $hash = "b013ececea83f4d6d8d2a29ac7c1b448"; 202 my $outfile = "dvb-ttusb-dec-3000s.fw"; 203 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 204 205 checkstandard(); 206 207 wgetfile($sourcefile, $url); 208 unzip($sourcefile, $tmpdir); 209 verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_S.bin", $hash); 210 copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_S.bin", $outfile); 211 212 $outfile; 213} 214sub opera1{ 215 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0); 216 217 checkstandard(); 218 my $fwfile1="dvb-usb-opera1-fpga-01.fw"; 219 my $fwfile2="dvb-usb-opera-01.fw"; 220 extract("2830SCap2.sys", 0x62e8, 55024, "$tmpdir/opera1-fpga.fw"); 221 extract("2830SLoad2.sys",0x3178,0x3685-0x3178,"$tmpdir/fw1part1"); 222 extract("2830SLoad2.sys",0x0980,0x3150-0x0980,"$tmpdir/fw1part2"); 223 delzero("$tmpdir/fw1part1","$tmpdir/fw1part1-1"); 224 delzero("$tmpdir/fw1part2","$tmpdir/fw1part2-1"); 225 verify("$tmpdir/fw1part1-1","5e0909858fdf0b5b09ad48b9fe622e70"); 226 verify("$tmpdir/fw1part2-1","d6e146f321427e931df2c6fcadac37a1"); 227 verify("$tmpdir/opera1-fpga.fw","0f8133f5e9051f5f3c1928f7e5a1b07d"); 228 229 my $RES1="\x01\x92\x7f\x00\x01\x00"; 230 my $RES0="\x01\x92\x7f\x00\x00\x00"; 231 my $DAT1="\x01\x00\xe6\x00\x01\x00"; 232 my $DAT0="\x01\x00\xe6\x00\x00\x00"; 233 open FW,">$tmpdir/opera.fw"; 234 print FW "$RES1"; 235 print FW "$DAT1"; 236 print FW "$RES1"; 237 print FW "$DAT1"; 238 appendfile(FW,"$tmpdir/fw1part1-1"); 239 print FW "$RES0"; 240 print FW "$DAT0"; 241 print FW "$RES1"; 242 print FW "$DAT1"; 243 appendfile(FW,"$tmpdir/fw1part2-1"); 244 print FW "$RES1"; 245 print FW "$DAT1"; 246 print FW "$RES0"; 247 print FW "$DAT0"; 248 copy ("$tmpdir/opera1-fpga.fw",$fwfile1); 249 copy ("$tmpdir/opera.fw",$fwfile2); 250 251 $fwfile1.",".$fwfile2; 252} 253 254sub vp7041 { 255 my $sourcefile = "2.422.zip"; 256 my $url = "http://www.twinhan.com/files/driver/USB-Ter/$sourcefile"; 257 my $hash = "e88c9372d1f66609a3e7b072c53fbcfe"; 258 my $outfile = "dvb-vp7041-2.422.fw"; 259 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 260 261 checkstandard(); 262 263 wgetfile($sourcefile, $url); 264 unzip($sourcefile, $tmpdir); 265 extract("$tmpdir/VisionDTV/Drivers/Win2K&XP/UDTTload.sys", 12503, 3036, "$tmpdir/fwtmp1"); 266 extract("$tmpdir/VisionDTV/Drivers/Win2K&XP/UDTTload.sys", 2207, 10274, "$tmpdir/fwtmp2"); 267 268 my $CMD = "\000\001\000\222\177\000"; 269 my $PAD = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"; 270 my ($FW); 271 open $FW, ">$tmpdir/fwtmp3"; 272 print $FW "$CMD\001$PAD"; 273 print $FW "$CMD\001$PAD"; 274 appendfile($FW, "$tmpdir/fwtmp1"); 275 print $FW "$CMD\000$PAD"; 276 print $FW "$CMD\001$PAD"; 277 appendfile($FW, "$tmpdir/fwtmp2"); 278 print $FW "$CMD\001$PAD"; 279 print $FW "$CMD\000$PAD"; 280 close($FW); 281 282 verify("$tmpdir/fwtmp3", $hash); 283 copy("$tmpdir/fwtmp3", $outfile); 284 285 $outfile; 286} 287 288sub dibusb { 289 my $url = "http://www.linuxtv.org/downloads/firmware/dvb-usb-dibusb-5.0.0.11.fw"; 290 my $outfile = "dvb-dibusb-5.0.0.11.fw"; 291 my $hash = "fa490295a527360ca16dcdf3224ca243"; 292 293 checkstandard(); 294 295 wgetfile($outfile, $url); 296 verify($outfile,$hash); 297 298 $outfile; 299} 300 301sub nxt2002 { 302 my $sourcefile = "Technisat_DVB-PC_4_4_COMPACT.zip"; 303 my $url = "http://www.bbti.us/download/windows/$sourcefile"; 304 my $hash = "476befae8c7c1bb9648954060b1eec1f"; 305 my $outfile = "dvb-fe-nxt2002.fw"; 306 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 307 308 checkstandard(); 309 310 wgetfile($sourcefile, $url); 311 unzip($sourcefile, $tmpdir); 312 verify("$tmpdir/SkyNET.sys", $hash); 313 extract("$tmpdir/SkyNET.sys", 331624, 5908, $outfile); 314 315 $outfile; 316} 317 318sub nxt2004 { 319 my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip"; 320 my $url = "http://www.aver.com/support/Drivers/$sourcefile"; 321 my $hash = "111cb885b1e009188346d72acfed024c"; 322 my $outfile = "dvb-fe-nxt2004.fw"; 323 my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1); 324 325 checkstandard(); 326 327 wgetfile($sourcefile, $url); 328 unzip($sourcefile, $tmpdir); 329 verify("$tmpdir/3xHybrid.sys", $hash); 330 extract("$tmpdir/3xHybrid.sys", 465304, 9584, $outfile); 331 332 $outfile; 333} 334 335sub or51211 { 336 my $fwfile = "dvb-fe-or51211.fw"; 337 my $url = "http://linuxtv.org/downloads/firmware/$fwfile"; 338 my $hash = "d830949c771a289505bf9eafc225d491"; 339 340 checkstandard(); 341 342 wgetfile($fwfile, $url); 343 verify($fwfile, $hash); 344 345 $fwfile; 346} 347 348sub or51132_qam { 349 my $fwfile = "dvb-fe-or51132-qam.fw"; 350 my $url = "http://linuxtv.org/downloads/firmware/$fwfile"; 351 my $hash = "7702e8938612de46ccadfe9b413cb3b5"; 352 353 checkstandard(); 354 355 wgetfile($fwfile, $url); 356 verify($fwfile, $hash); 357 358 $fwfile; 359} 360 361sub or51132_vsb { 362 my $fwfile = "dvb-fe-or51132-vsb.fw"; 363 my $url = "http://linuxtv.org/downloads/firmware/$fwfile"; 364 my $hash = "c16208e02f36fc439a557ad4c613364a"; 365 366 checkstandard(); 367 368 wgetfile($fwfile, $url); 369 verify($fwfile, $hash); 370 371 $fwfile; 372} 373 374sub bluebird { 375 my $url = "http://www.linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw"; 376 my $outfile = "dvb-usb-bluebird-01.fw"; 377 my $hash = "658397cb9eba9101af9031302671f49d"; 378 379 checkstandard(); 380 381 wgetfile($outfile, $url); 382 verify($outfile,$hash); 383 384 $outfile; 385} 386 387# --------------------------------------------------------------- 388# Utilities 389 390sub checkstandard { 391 if (system("which unzip > /dev/null 2>&1")) { 392 die "This firmware requires the unzip command - see ftp://ftp.info-zip.org/pub/infozip/UnZip.html\n"; 393 } 394 if (system("which md5sum > /dev/null 2>&1")) { 395 die "This firmware requires the md5sum command - see http://www.gnu.org/software/coreutils/\n"; 396 } 397 if (system("which wget > /dev/null 2>&1")) { 398 die "This firmware requires the wget command - see http://wget.sunsite.dk/\n"; 399 } 400} 401 402sub checkunshield { 403 if (system("which unshield > /dev/null 2>&1")) { 404 die "This firmware requires the unshield command - see http://sourceforge.net/projects/synce/\n"; 405 } 406} 407 408sub wgetfile { 409 my ($sourcefile, $url) = @_; 410 411 if (! -f $sourcefile) { 412 system("wget -O \"$sourcefile\" \"$url\"") and die "wget failed - unable to download firmware"; 413 } 414} 415 416sub unzip { 417 my ($sourcefile, $todir) = @_; 418 419 $status = system("unzip -q -o -d \"$todir\" \"$sourcefile\" 2>/dev/null" ); 420 if ((($status >> 8) > 2) || (($status & 0xff) != 0)) { 421 die ("unzip failed - unable to extract firmware"); 422 } 423} 424 425sub unshield { 426 my ($sourcefile, $todir) = @_; 427 428 system("unshield x -d \"$todir\" \"$sourcefile\" > /dev/null" ) and die ("unshield failed - unable to extract firmware"); 429} 430 431sub verify { 432 my ($filename, $hash) = @_; 433 my ($testhash); 434 435 open(CMD, "md5sum \"$filename\"|"); 436 $testhash = <CMD>; 437 $testhash =~ /([a-zA-Z0-9]*)/; 438 $testhash = $1; 439 close CMD; 440 die "Hash of extracted file does not match!\n" if ($testhash ne $hash); 441} 442 443sub copy { 444 my ($from, $to) = @_; 445 446 system("cp -f \"$from\" \"$to\"") and die ("cp failed"); 447} 448 449sub extract { 450 my ($infile, $offset, $length, $outfile) = @_; 451 my ($chunklength, $buf, $rcount); 452 453 open INFILE, "<$infile"; 454 open OUTFILE, ">$outfile"; 455 sysseek(INFILE, $offset, SEEK_SET); 456 while($length > 0) { 457 # Calc chunk size 458 $chunklength = 2048; 459 $chunklength = $length if ($chunklength > $length); 460 461 $rcount = sysread(INFILE, $buf, $chunklength); 462 die "Ran out of data\n" if ($rcount != $chunklength); 463 syswrite(OUTFILE, $buf); 464 $length -= $rcount; 465 } 466 close INFILE; 467 close OUTFILE; 468} 469 470sub appendfile { 471 my ($FH, $infile) = @_; 472 my ($buf); 473 474 open INFILE, "<$infile"; 475 while(1) { 476 $rcount = sysread(INFILE, $buf, 2048); 477 last if ($rcount == 0); 478 print $FH $buf; 479 } 480 close(INFILE); 481} 482 483sub delzero{ 484 my ($infile,$outfile) =@_; 485 486 open INFILE,"<$infile"; 487 open OUTFILE,">$outfile"; 488 while (1){ 489 $rcount=sysread(INFILE,$buf,22); 490 $len=ord(substr($buf,0,1)); 491 print OUTFILE substr($buf,0,1); 492 print OUTFILE substr($buf,2,$len+3); 493 last if ($rcount<1); 494 printf OUTFILE "%c",0; 495#print $len." ".length($buf)."\n"; 496 497 } 498 close(INFILE); 499 close(OUTFILE); 500} 501 502sub syntax() { 503 print STDERR "syntax: get_dvb_firmware <component>\n"; 504 print STDERR "Supported components:\n"; 505 for($i=0; $i < scalar(@components); $i++) { 506 print STDERR "\t" . $components[$i] . "\n"; 507 } 508 exit(1); 509} 510