#!/usr/bin/perl
use strict;
use File::Find;

my %depend = ();
my %depend2 = ();
my %rmlist = ();
my @nodep;
my @modlist;
my @allmodules;
my %reqmodules;
my %loaded = ();
my $i=0;

# Device debug parameters
#		Module name		   Debug option
my %debug = (	"tuner"			=> "tuner_debug=1",
		"dvb-core"		=> "cam_debug=1",
		"dvb-ttpci"		=> "debug=247",
		"b2c2-flexcop"		=> "debug=0x01",
		"b2c2-flexcop-usb"	=> "debug=0x01",
		"b2c2-flexcop-pci"	=> "debug=0x01",
		"dvb-usb"		=> "debug=0x33",
		"dvb-usb-gp8psk"	=> "debug=0x03",
		"dvb-usb-vp7045"	=> "debug=0x03",
		"dvb-usb-dtt200u"	=> "debug=0x03",
		"dvb-usb-dibusb-common"	=> "debug=0x03",
	    );


sub parse_dir {
	my $file = $File::Find::name;

	if (!($file =~ /[.]ko$/)) {
		return;
	}

	my $module = $file;
	$module =~ s|^[./]*(.*)[.]ko|\1|;

	open IN,  "modinfo $file|grep depends|cut -b 17-|";
	while (<IN>) {
		my $deps = $_;
		$deps =~ s/\n//;
		$deps =~ s/[,]/ /g;
		$deps = " $deps ";
		$depend{$module} = $deps;
		push @allmodules, $module;
		$i++;
	}
	close IN;
}

sub parse_loaded {
	open IN,  "/proc/modules";
	while (<IN>) {
		m/^([\w\d_-]+)/;
		$loaded{$1}=1;
	}
	close IN;
}

sub cleandep()
{
	my $dep;

	while ( my ($k, $v) = each(%depend) ) {
		my $arg=$v;
		my $arg2=" ";
		while (!($arg =~ m/^\s*$/)) {
			if ($arg =~ m/^ ([^ ]+) /) {
				my $val=$1;
				if (exists($depend{$val})) {
					$arg2="$arg2 $val ";
				} else {
					$reqmodules{$val}=1;
				}
			}
			$arg =~ s/^ [^ ]+//;
			$arg2 =~ s/\s\s+/ /;
		}
		$depend2 { $k } = $arg2;
	}

}

sub rmdep()
{
	my $dep;

	while ($dep=pop @nodep) {
		while ( my ($k, $v) = each(%depend2) ) {
			if ($v =~ m/\s($dep)\s/) {
				$v =~ s/\s${dep}\s/ /;
				$v =~ s/\s${dep}\s/ /;
				$v =~ s/\s${dep}\s/ /;
				$depend2 {$k} = $v;
			}
		}
	}
}

sub orderdep ()
{
	my $old;
	do {
		$old=$i;
		while ( my ($key, $value) = each(%depend2) ) {
			if ($value =~ m/^\s*$/) {
				push @nodep, $key;
				push @modlist, $key;
				$i=$i-1;
				delete $depend2 {$key};
			}
		}
		rmdep();
	} until ($old==$i);
	while ( my ($key, $value) = each(%depend2) ) {
		printf "ERROR: bad dependencies - $key ($value)\n";
	}
}

sub insmod ($)
{
	my $debug=shift;

	while ( my ($key, $value) = each(%reqmodules) ) {
		printf ("modprobe $key\n");
		system ("modprobe $key");
	}

	foreach my $key (@modlist) {
		if ($debug) {
			my $dbg=$debug{$key};

			printf "insmod ./$key.ko $dbg\n";
			system "insmod ./$key.ko $dbg\n";
		} else {
			printf "insmod ./$key.ko\n";
			system "insmod ./$key.ko\n";
		}
	}
}

sub rmmod ()
{
	while (my $key=pop @modlist) {
		my $dep=$key;
		$dep=~s/[\-]/_/g;
		if (exists ($loaded{$dep})) {
			printf "rmmod $dep\n";
			system "rmmod $dep\n";
		}
	}
}

sub prepare_cmd()
{
	find(\&parse_dir, ".");
	printf "found $i modules\n";

	cleandep();
	orderdep();
}

# main
my $mode=shift;
if ($mode eq "load") {
		prepare_cmd;
		insmod(0);
} else {
	if ($mode eq "unload") {
		prepare_cmd;
		parse_loaded;
		rmmod;
	} else {
		if ($mode eq "reload") {
			prepare_cmd;
			parse_loaded;
			my @modlist2=@modlist;
			rmmod;
			@modlist=@modlist2;
			insmod(0);
		} else {
			if ($mode eq "debug") {
				prepare_cmd;
				parse_loaded;
				insmod(1);
			} else {
				printf "Usage: $0 [load|unload|reload]\n";
			}
		}
	}
}