aboutsummaryrefslogtreecommitdiffstats
path: root/net/llc
Commit message (Expand)AuthorAge
* [NET]: Conversions from kmalloc+memset to k(z|c)alloc.Panagiotis Issaris2006-07-21
* Remove obsolete #include <linux/config.h>Jörn Engel2006-06-30
* [LLC]: Fix double receive of SKB.Andrew Morton2006-06-18
* [LLC]: add multicast support for datagramsStephen Hemminger2006-06-18
* [LLC]: allow applications to get copy of kernel datagramsStephen Hemminger2006-06-18
* [LLC]: use rcu_dereference on receive handlerStephen Hemminger2006-06-18
* [LLC]: allow datagram recvmsgStephen Hemminger2006-06-18
* [LLC]: use more efficient ether address routinesStephen Hemminger2006-06-18
* [I/OAT]: Make sk_eat_skb I/OAT aware.Chris Leech2006-06-18
* [LLC]: Use pskb_trim_rcsum() in llc_fixup_skb().David S. Miller2006-04-19
* [LLC]: llc_mac_hdr_init const argumentsStephen Hemminger2006-03-21
* [LLC]: Fix sap refcountingArnaldo Carvalho de Melo2006-03-21
* [LLC]: Replace __inline__ with inlineArnaldo Carvalho de Melo2006-03-21
* [LLC]: Fix struct proto .nameArnaldo Carvalho de Melo2006-03-21
* [NET]: Add a dev_ioctl() fallback to sock_ioctl()Christoph Hellwig2006-01-03
* [NET]: move struct proto_ops to constEric Dumazet2006-01-03
* [NET]: Avoid atomic xchg() for non-error caseBenjamin LaHaise2006-01-03
* [LLC]: Fix compiler warnings introduced by TX window scaling changes.David S. Miller2005-11-17
* [LLC]: Make core block on remote busy.Jochen Friedrich2005-11-15
* [LLC]: Fix TX window scalingJochen Friedrich2005-11-15
* [PATCH] gfp flags annotations - part 1Al Viro2005-10-08
* [LLC]: fix llc_ui_recvmsg, making it behave like tcp_recvmsgArnaldo Carvalho de Melo2005-09-22
* [LLC]: Fix the accept pathArnaldo Carvalho de Melo2005-09-22
* [LLC]: Fix sparse warningsArnaldo Carvalho de Melo2005-09-22
* [LLC]: Fix llc_fixup_skb() bugJochen Friedrich2005-09-22
* [LLC]: Fix for Bugzilla ticket #5157Jochen Friedrich2005-09-22
* [LLC]: Fix for Bugzilla ticket #5156Jochen Friedrich2005-09-22
* [LLC]: Use refcounting with struct llc_sapArnaldo Carvalho de Melo2005-09-22
* [LLC]: Do better struct sock accounting on skbsArnaldo Carvalho de Melo2005-09-22
* [LLC]: Use sk_wait_dataArnaldo Carvalho de Melo2005-09-22
* [LLC]: Use some more likely/unlikelyArnaldo Carvalho de Melo2005-09-22
* [LLC]: Add sysctl support for the LLC timeoutsArnaldo Carvalho de Melo2005-09-22
* [LLC]: Use the sk_wait_event primitiveArnaldo Carvalho de Melo2005-09-22
* [LLC]: Convert llc_ui_wait_for_ functions to use prepare_to_wait/finish_waitArnaldo Carvalho de Melo2005-09-22
* [LLC]: Remove unused functions from llc_c_ev.cArnaldo Carvalho de Melo2005-09-22
* [LLC]: Use const in llc_c_ev.cArnaldo Carvalho de Melo2005-09-22
* [LLC]: Help the compiler with likely/unlikely, saving some more bytesArnaldo Carvalho de Melo2005-09-22
* [LLC]: Mark llc_find_next_offset as __init, saving some more bytesArnaldo Carvalho de Melo2005-09-22
* [LLC]: Update comments for llc_ui_bind and llc_ui_autobind to match new behav...Arnaldo Carvalho de Melo2005-09-22
* [LLC]: Remove unneeded temp net_device variablesArnaldo Carvalho de Melo2005-09-22
* [LLC]: introduce llc_conn_tmr_common_cb, to avoid code duplicationArnaldo Carvalho de Melo2005-09-22
* [LLC]: Remove unneeded f_bit variablesArnaldo Carvalho de Melo2005-09-22
* [LLC]: Simplify llc_c_ac code, removing unneeded assignments to variablesArnaldo Carvalho de Melo2005-09-22
* [LLC]: Make llc_frame_alloc take a net_device as an argumentArnaldo Carvalho de Melo2005-09-22
* [TCP]: Move the tcp sock states to net/tcp_states.hArnaldo Carvalho de Melo2005-08-29
* [NET]: Kill skb->real_devDavid S. Miller2005-08-29
* [NET]: Kill skb->listDavid S. Miller2005-08-29
* [NET]: Transform skb_queue_len() binary tests into skb_queue_empty()David S. Miller2005-07-08
* Linux-2.6.12-rc2v2.6.12-rc2Linus Torvalds2005-04-16
>599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710
#!/usr/bin/perl
#     DVB firmware extractor
#
#     (c) 2004 Andrew de Quincey
#
#     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; either version 2 of the License, or
#       (at your option) any later version.
#
#     This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#
#     GNU General Public License for more details.
#
#     You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

use File::Temp qw/ tempdir /;
use IO::Handle;

@components = ( "sp8870", "sp887x", "tda10045", "tda10046",
		"tda10046lifeview", "av7110", "dec2000t", "dec2540t",
		"dec3000s", "vp7041", "dibusb", "nxt2002", "nxt2004",
		"or51211", "or51132_qam", "or51132_vsb", "bluebird",
		"opera1", "cx231xx", "cx18", "cx23885", "pvrusb2", "mpc718",
		"af9015", "ngene", "az6027");

# Check args
syntax() if (scalar(@ARGV) != 1);
$cid = $ARGV[0];

# Do it!
for ($i=0; $i < scalar(@components); $i++) {
    if ($cid eq $components[$i]) {
	$outfile = eval($cid);
	die $@ if $@;
	print STDERR <<EOF;
Firmware(s) $outfile extracted successfully.
Now copy it(them) to either /usr/lib/hotplug/firmware or /lib/firmware
(depending on configuration of firmware hotplug).
EOF
	exit(0);
    }
}

# If we get here, it wasn't found
print STDERR "Unknown component \"$cid\"\n";
syntax();




# ---------------------------------------------------------------
# Firmware-specific extraction subroutines

sub sp8870 {
    my $sourcefile = "tt_Premium_217g.zip";
    my $url = "http://www.softwarepatch.pl/9999ccd06a4813cb827dbb0005071c71/$sourcefile";
    my $hash = "53970ec17a538945a6d8cb608a7b3899";
    my $outfile = "dvb-fe-sp8870.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();

    wgetfile($sourcefile, $url);
    unzip($sourcefile, $tmpdir);
    verify("$tmpdir/software/OEM/HE/App/boot/SC_MAIN.MC", $hash);
    copy("$tmpdir/software/OEM/HE/App/boot/SC_MAIN.MC", $outfile);

    $outfile;
}

sub sp887x {
    my $sourcefile = "Dvbt1.3.57.6.zip";
    my $url = "http://www.avermedia.com/software/$sourcefile";
    my $cabfile = "DVBT Net  Ver1.3.57.6/disk1/data1.cab";
    my $hash = "237938d53a7f834c05c42b894ca68ac3";
    my $outfile = "dvb-fe-sp887x.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();
    checkunshield();

    wgetfile($sourcefile, $url);
    unzip($sourcefile, $tmpdir);
    unshield("$tmpdir/$cabfile", $tmpdir);
    verify("$tmpdir/ZEnglish/sc_main.mc", $hash);
    copy("$tmpdir/ZEnglish/sc_main.mc", $outfile);

    $outfile;
}

sub tda10045 {
    my $sourcefile = "tt_budget_217g.zip";
    my $url = "http://www.technotrend.de/new/217g/$sourcefile";
    my $hash = "2105fd5bf37842fbcdfa4bfd58f3594a";
    my $outfile = "dvb-fe-tda10045.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();

    wgetfile($sourcefile, $url);
    unzip($sourcefile, $tmpdir);
    extract("$tmpdir/software/OEM/PCI/App/ttlcdacc.dll", 0x37ef9, 30555, "$tmpdir/fwtmp");
    verify("$tmpdir/fwtmp", $hash);
    copy("$tmpdir/fwtmp", $outfile);

    $outfile;
}

sub tda10046 {
	my $sourcefile = "TT_PCI_2.19h_28_11_2006.zip";
	my $url = "http://www.tt-download.com/download/updates/219/$sourcefile";
	my $hash = "6a7e1e2f2644b162ff0502367553c72d";
	my $outfile = "dvb-fe-tda10046.fw";
	my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

	checkstandard();

	wgetfile($sourcefile, $url);
	unzip($sourcefile, $tmpdir);
	extract("$tmpdir/TT_PCI_2.19h_28_11_2006/software/OEM/PCI/App/ttlcdacc.dll", 0x65389, 24478, "$tmpdir/fwtmp");
	verify("$tmpdir/fwtmp", $hash);
	copy("$tmpdir/fwtmp", $outfile);

	$outfile;
}

sub tda10046lifeview {
    my $sourcefile = "7%5Cdrv_2.11.02.zip";
    my $url = "http://www.lifeview.hk/dbimages/document/$sourcefile";
    my $hash = "1ea24dee4eea8fe971686981f34fd2e0";
    my $outfile = "dvb-fe-tda10046.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();

    wgetfile($sourcefile, $url);
    unzip($sourcefile, $tmpdir);
    extract("$tmpdir/LVHybrid.sys", 0x8b088, 24602, "$tmpdir/fwtmp");
    verify("$tmpdir/fwtmp", $hash);
    copy("$tmpdir/fwtmp", $outfile);

    $outfile;
}

sub av7110 {
    my $sourcefile = "dvb-ttpci-01.fw-261d";
    my $url = "http://www.linuxtv.org/downloads/firmware/$sourcefile";
    my $hash = "603431b6259715a8e88f376a53b64e2f";
    my $outfile = "dvb-ttpci-01.fw";

    checkstandard();

    wgetfile($sourcefile, $url);
    verify($sourcefile, $hash);
    copy($sourcefile, $outfile);

    $outfile;
}

sub dec2000t {
    my $sourcefile = "dec217g.exe";
    my $url = "http://hauppauge.lightpath.net/de/$sourcefile";
    my $hash = "bd86f458cee4a8f0a8ce2d20c66215a9";
    my $outfile = "dvb-ttusb-dec-2000t.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();

    wgetfile($sourcefile, $url);
    unzip($sourcefile, $tmpdir);
    verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_T.bin", $hash);
    copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_T.bin", $outfile);

    $outfile;
}

sub dec2540t {
    my $sourcefile = "dec217g.exe";
    my $url = "http://hauppauge.lightpath.net/de/$sourcefile";
    my $hash = "53e58f4f5b5c2930beee74a7681fed92";
    my $outfile = "dvb-ttusb-dec-2540t.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();

    wgetfile($sourcefile, $url);
    unzip($sourcefile, $tmpdir);
    verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_X.bin", $hash);
    copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_X.bin", $outfile);

    $outfile;
}

sub dec3000s {
    my $sourcefile = "dec217g.exe";
    my $url = "http://hauppauge.lightpath.net/de/$sourcefile";
    my $hash = "b013ececea83f4d6d8d2a29ac7c1b448";
    my $outfile = "dvb-ttusb-dec-3000s.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();

    wgetfile($sourcefile, $url);
    unzip($sourcefile, $tmpdir);
    verify("$tmpdir/software/OEM/STB/App/Boot/STB_PC_S.bin", $hash);
    copy("$tmpdir/software/OEM/STB/App/Boot/STB_PC_S.bin", $outfile);

    $outfile;
}
sub opera1{
	my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 0);

	checkstandard();
	my $fwfile1="dvb-usb-opera1-fpga-01.fw";
	my $fwfile2="dvb-usb-opera-01.fw";
	extract("2830SCap2.sys", 0x62e8, 55024, "$tmpdir/opera1-fpga.fw");
	extract("2830SLoad2.sys",0x3178,0x3685-0x3178,"$tmpdir/fw1part1");
	extract("2830SLoad2.sys",0x0980,0x3150-0x0980,"$tmpdir/fw1part2");
	delzero("$tmpdir/fw1part1","$tmpdir/fw1part1-1");
	delzero("$tmpdir/fw1part2","$tmpdir/fw1part2-1");
	verify("$tmpdir/fw1part1-1","5e0909858fdf0b5b09ad48b9fe622e70");
	verify("$tmpdir/fw1part2-1","d6e146f321427e931df2c6fcadac37a1");
	verify("$tmpdir/opera1-fpga.fw","0f8133f5e9051f5f3c1928f7e5a1b07d");

	my $RES1="\x01\x92\x7f\x00\x01\x00";
	my $RES0="\x01\x92\x7f\x00\x00\x00";
	my $DAT1="\x01\x00\xe6\x00\x01\x00";
	my $DAT0="\x01\x00\xe6\x00\x00\x00";
	open FW,">$tmpdir/opera.fw";
	print FW "$RES1";
	print FW "$DAT1";
	print FW "$RES1";
	print FW "$DAT1";
	appendfile(FW,"$tmpdir/fw1part1-1");
	print FW "$RES0";
	print FW "$DAT0";
	print FW "$RES1";
	print FW "$DAT1";
	appendfile(FW,"$tmpdir/fw1part2-1");
	print FW "$RES1";
	print FW "$DAT1";
	print FW "$RES0";
	print FW "$DAT0";
	copy ("$tmpdir/opera1-fpga.fw",$fwfile1);
	copy ("$tmpdir/opera.fw",$fwfile2);

	$fwfile1.",".$fwfile2;
}

sub vp7041 {
    my $sourcefile = "2.422.zip";
    my $url = "http://www.twinhan.com/files/driver/USB-Ter/$sourcefile";
    my $hash = "e88c9372d1f66609a3e7b072c53fbcfe";
    my $outfile = "dvb-vp7041-2.422.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();

    wgetfile($sourcefile, $url);
    unzip($sourcefile, $tmpdir);
    extract("$tmpdir/VisionDTV/Drivers/Win2K&XP/UDTTload.sys", 12503, 3036, "$tmpdir/fwtmp1");
    extract("$tmpdir/VisionDTV/Drivers/Win2K&XP/UDTTload.sys", 2207, 10274, "$tmpdir/fwtmp2");

    my $CMD = "\000\001\000\222\177\000";
    my $PAD = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000";
    my ($FW);
    open $FW, ">$tmpdir/fwtmp3";
    print $FW "$CMD\001$PAD";
    print $FW "$CMD\001$PAD";
    appendfile($FW, "$tmpdir/fwtmp1");
    print $FW "$CMD\000$PAD";
    print $FW "$CMD\001$PAD";
    appendfile($FW, "$tmpdir/fwtmp2");
    print $FW "$CMD\001$PAD";
    print $FW "$CMD\000$PAD";
    close($FW);

    verify("$tmpdir/fwtmp3", $hash);
    copy("$tmpdir/fwtmp3", $outfile);

    $outfile;
}

sub dibusb {
	my $url = "http://www.linuxtv.org/downloads/firmware/dvb-usb-dibusb-5.0.0.11.fw";
	my $outfile = "dvb-dibusb-5.0.0.11.fw";
	my $hash = "fa490295a527360ca16dcdf3224ca243";

	checkstandard();

	wgetfile($outfile, $url);
	verify($outfile,$hash);

	$outfile;
}

sub nxt2002 {
    my $sourcefile = "Technisat_DVB-PC_4_4_COMPACT.zip";
    my $url = "http://www.bbti.us/download/windows/$sourcefile";
    my $hash = "476befae8c7c1bb9648954060b1eec1f";
    my $outfile = "dvb-fe-nxt2002.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();

    wgetfile($sourcefile, $url);
    unzip($sourcefile, $tmpdir);
    verify("$tmpdir/SkyNET.sys", $hash);
    extract("$tmpdir/SkyNET.sys", 331624, 5908, $outfile);

    $outfile;
}

sub nxt2004 {
    my $sourcefile = "AVerTVHD_MCE_A180_Drv_v1.2.2.16.zip";
    my $url = "http://www.avermedia-usa.com/support/Drivers/$sourcefile";
    my $hash = "111cb885b1e009188346d72acfed024c";
    my $outfile = "dvb-fe-nxt2004.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();

    wgetfile($sourcefile, $url);
    unzip($sourcefile, $tmpdir);
    verify("$tmpdir/3xHybrid.sys", $hash);
    extract("$tmpdir/3xHybrid.sys", 465304, 9584, $outfile);

    $outfile;
}

sub or51211 {
    my $fwfile = "dvb-fe-or51211.fw";
    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
    my $hash = "d830949c771a289505bf9eafc225d491";

    checkstandard();

    wgetfile($fwfile, $url);
    verify($fwfile, $hash);

    $fwfile;
}

sub cx231xx {
    my $fwfile = "v4l-cx231xx-avcore-01.fw";
    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
    my $hash = "7d3bb956dc9df0eafded2b56ba57cc42";

    checkstandard();

    wgetfile($fwfile, $url);
    verify($fwfile, $hash);

    $fwfile;
}

sub cx18 {
    my $url = "http://linuxtv.org/downloads/firmware/";

    my %files = (
	'v4l-cx23418-apu.fw' => '588f081b562f5c653a3db1ad8f65939a',
	'v4l-cx23418-cpu.fw' => 'b6c7ed64bc44b1a6e0840adaeac39d79',
	'v4l-cx23418-dig.fw' => '95bc688d3e7599fd5800161e9971cc55',
    );

    checkstandard();

    my $allfiles;
    foreach my $fwfile (keys %files) {
	wgetfile($fwfile, "$url/$fwfile");
	verify($fwfile, $files{$fwfile});
	$allfiles .= " $fwfile";
    }

    $allfiles =~ s/^\s//;

    $allfiles;
}

sub mpc718 {
    my $archive = 'Yuan MPC718 TV Tuner Card 2.13.10.1016.zip';
    my $url = "ftp://ftp.work.acer-euro.com/desktop/aspire_idea510/vista/Drivers/$archive";
    my $fwfile = "dvb-cx18-mpc718-mt352.fw";
    my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);

    checkstandard();
    wgetfile($archive, $url);
    unzip($archive, $tmpdir);

    my $sourcefile = "$tmpdir/Yuan MPC718 TV Tuner Card 2.13.10.1016/mpc718_32bit/yuanrap.sys";
    my $found = 0;

    open IN, '<', $sourcefile or die "Couldn't open $sourcefile to extract $fwfile data\n";
    binmode IN;
    open OUT, '>', $fwfile;
    binmode OUT;
    {
	# Block scope because we change the line terminator variable $/
	my $prevlen = 0;
	my $currlen;

	# Buried in the data segment are 3 runs of almost identical
	# register-value pairs that end in 0x5d 0x01 which is a "TUNER GO"
	# command for the MT352.
	# Pull out the middle run (because it's easy) of register-value
	# pairs to make the "firmware" file.

	local $/ = "\x5d\x01"; # MT352 "TUNER GO"

	while (<IN>) {
	    $currlen = length($_);
	    if ($prevlen == $currlen && $currlen <= 64) {
		chop; chop; # Get rid of "TUNER GO"
		s/^\0\0//;  # get rid of leading 00 00 if it's there
		printf OUT "$_";
		$found = 1;
		last;
	    }
	    $prevlen = $currlen;
	}
    }
    close OUT;
    close IN;
    if (!$found) {
	unlink $fwfile;
	die "Couldn't find valid register-value sequence in $sourcefile for $fwfile\n";
    }
    $fwfile;
}

sub cx23885 {
    my $url = "http://linuxtv.org/downloads/firmware/";

    my %files = (
	'v4l-cx23885-avcore-01.fw' => 'a9f8f5d901a7fb42f552e1ee6384f3bb',
	'v4l-cx23885-enc.fw'       => 'a9f8f5d901a7fb42f552e1ee6384f3bb',
    );

    checkstandard();

    my $allfiles;
    foreach my $fwfile (keys %files) {
	wgetfile($fwfile, "$url/$fwfile");
	verify($fwfile, $files{$fwfile});
	$allfiles .= " $fwfile";
    }

    $allfiles =~ s/^\s//;

    $allfiles;
}

sub pvrusb2 {
    my $url = "http://linuxtv.org/downloads/firmware/";

    my %files = (
	'v4l-cx25840.fw'           => 'dadb79e9904fc8af96e8111d9cb59320',
    );

    checkstandard();

    my $allfiles;
    foreach my $fwfile (keys %files) {
	wgetfile($fwfile, "$url/$fwfile");
	verify($fwfile, $files{$fwfile});
	$allfiles .= " $fwfile";
    }

    $allfiles =~ s/^\s//;

    $allfiles;
}

sub or51132_qam {
    my $fwfile = "dvb-fe-or51132-qam.fw";
    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
    my $hash = "7702e8938612de46ccadfe9b413cb3b5";

    checkstandard();

    wgetfile($fwfile, $url);
    verify($fwfile, $hash);

    $fwfile;
}

sub or51132_vsb {
    my $fwfile = "dvb-fe-or51132-vsb.fw";
    my $url = "http://linuxtv.org/downloads/firmware/$fwfile";
    my $hash = "c16208e02f36fc439a557ad4c613364a";

    checkstandard();

    wgetfile($fwfile, $url);
    verify($fwfile, $hash);

    $fwfile;
}

sub bluebird {
	my $url = "http://www.linuxtv.org/download/dvb/firmware/dvb-usb-bluebird-01.fw";
	my $outfile = "dvb-usb-bluebird-01.fw";
	my $hash = "658397cb9eba9101af9031302671f49d";

	checkstandard();

	wgetfile($outfile, $url);
	verify($outfile,$hash);

	$outfile;
}

sub af9015 {
	my $sourcefile = "download.ashx?file=57";
	my $url = "http://www.ite.com.tw/EN/Services/$sourcefile";
	my $hash = "e3f08935158038d385ad382442f4bb2d";
	my $outfile = "dvb-usb-af9015.fw";
	my $tmpdir = tempdir(DIR => "/tmp", CLEANUP => 1);
	my $fwoffset = 0x25690;
	my $fwlength = 18725;
	my ($chunklength, $buf, $rcount);

	checkstandard();

	wgetfile($sourcefile, $url);
	unzip($sourcefile, $tmpdir);
	verify("$tmpdir/Driver/Files/AF15BDA.sys", $hash);

	open INFILE, '<', "$tmpdir/Driver/Files/AF15BDA.sys";
	open OUTFILE, '>', $outfile;

	sysseek(INFILE, $fwoffset, SEEK_SET);
	while($fwlength > 0) {
		$chunklength = 55;
		$chunklength = $fwlength if ($chunklength > $fwlength);
		$rcount = sysread(INFILE, $buf, $chunklength);
		die "Ran out of data\n" if ($rcount != $chunklength);
		syswrite(OUTFILE, $buf);
		sysread(INFILE, $buf, 8);
		$fwlength -= $rcount + 8;
	}

	close OUTFILE;
	close INFILE;
}

sub ngene {
    my $url = "http://www.digitaldevices.de/download/";
    my $file1 = "ngene_15.fw";
    my $hash1 = "d798d5a757121174f0dbc5f2833c0c85";
    my $file2 = "ngene_17.fw";
    my $hash2 = "26b687136e127b8ac24b81e0eeafc20b";

    checkstandard();

    wgetfile($file1, $url . $file1);
    verify($file1, $hash1);

    wgetfile($file2, $url . $file2);
    verify($file2, $hash2);

    "$file1, $file2";
}

sub az6027{
    my $file = "AZ6027_Linux_Driver.tar.gz";
    my $url = "http://linux.terratec.de/files/$file";
    my $firmware = "dvb-usb-az6027-03.fw";

    wgetfile($file, $url);

    #untar
    if( system("tar xzvf $file $firmware")){
        die "failed to untar firmware";
    }
    if( system("rm $file")){
        die ("unable to remove unnecessary files");
    }

    $firmware;
}
# ---------------------------------------------------------------
# Utilities

sub checkstandard {
    if (system("which unzip > /dev/null 2>&1")) {
	die "This firmware requires the unzip command - see ftp://ftp.info-zip.org/pub/infozip/UnZip.html\n";
    }
    if (system("which md5sum > /dev/null 2>&1")) {
	die "This firmware requires the md5sum command - see http://www.gnu.org/software/coreutils/\n";
    }
    if (system("which wget > /dev/null 2>&1")) {
	die "This firmware requires the wget command - see http://wget.sunsite.dk/\n";
    }
}

sub checkunshield {
    if (system("which unshield > /dev/null 2>&1")) {
	die "This firmware requires the unshield command - see http://sourceforge.net/projects/synce/\n";
    }
}

sub wgetfile {
    my ($sourcefile, $url) = @_;

    if (! -f $sourcefile) {
	system("wget -O \"$sourcefile\" \"$url\"") and die "wget failed - unable to download firmware";
    }
}

sub unzip {
    my ($sourcefile, $todir) = @_;

    $status = system("unzip -q -o -d \"$todir\" \"$sourcefile\" 2>/dev/null" );
    if ((($status >> 8) > 2) || (($status & 0xff) != 0)) {
	die ("unzip failed - unable to extract firmware");
    }
}

sub unshield {
    my ($sourcefile, $todir) = @_;

    system("unshield x -d \"$todir\" \"$sourcefile\" > /dev/null" ) and die ("unshield failed - unable to extract firmware");
}

sub verify {
    my ($filename, $hash) = @_;
    my ($testhash);

    open(CMD, "md5sum \"$filename\"|");
    $testhash = <CMD>;
    $testhash =~ /([a-zA-Z0-9]*)/;
    $testhash = $1;
    close CMD;
    die "Hash of extracted file does not match!\n" if ($testhash ne $hash);
}

sub copy {
    my ($from, $to) = @_;

    system("cp -f \"$from\" \"$to\"") and die ("cp failed");
}

sub extract {
    my ($infile, $offset, $length, $outfile) = @_;
    my ($chunklength, $buf, $rcount);

    open INFILE, "<$infile";
    open OUTFILE, ">$outfile";
    sysseek(INFILE, $offset, SEEK_SET);
    while($length > 0) {
	# Calc chunk size
	$chunklength = 2048;
	$chunklength = $length if ($chunklength > $length);

	$rcount = sysread(INFILE, $buf, $chunklength);
	die "Ran out of data\n" if ($rcount != $chunklength);
	syswrite(OUTFILE, $buf);
	$length -= $rcount;
    }
    close INFILE;
    close OUTFILE;
}

sub appendfile {
    my ($FH, $infile) = @_;
    my ($buf);

    open INFILE, "<$infile";
    while(1) {
	$rcount = sysread(INFILE, $buf, 2048);
	last if ($rcount == 0);
	print $FH $buf;
    }
    close(INFILE);
}

sub delzero{
	my ($infile,$outfile) =@_;

	open INFILE,"<$infile";
	open OUTFILE,">$outfile";
	while (1){
		$rcount=sysread(INFILE,$buf,22);
		$len=ord(substr($buf,0,1));
		print OUTFILE substr($buf,0,1);
		print OUTFILE substr($buf,2,$len+3);
	last if ($rcount<1);
	printf OUTFILE "%c",0;
#print $len." ".length($buf)."\n";

	}
	close(INFILE);
	close(OUTFILE);
}

sub syntax() {
    print STDERR "syntax: get_dvb_firmware <component>\n";
    print STDERR "Supported components:\n";
    @components = sort @components;
    for($i=0; $i < scalar(@components); $i++) {
	print STDERR "\t" . $components[$i] . "\n";
    }
    exit(1);
}