diff options
-rwxr-xr-x | v4l/scripts/make_kconfig.pl | 465 |
1 files changed, 264 insertions, 201 deletions
diff --git a/v4l/scripts/make_kconfig.pl b/v4l/scripts/make_kconfig.pl index a9db697e9..6f1b108c1 100755 --- a/v4l/scripts/make_kconfig.pl +++ b/v4l/scripts/make_kconfig.pl @@ -1,5 +1,6 @@ #!/usr/bin/perl use FileHandle; +use strict; my %depend = (); my %minver = (); @@ -9,18 +10,18 @@ my %hexopt = (); my %tristate = (); my %kernopts = (); my %depmods = (); -my $version, $level, $sublevel, $kernver; +my ($version, $level, $sublevel, $kernver); -my $kernel=shift; -my $force_kconfig=shift; +my $kernel = shift; +my $force_kconfig = shift; my $debug=0; ########################################################### # Read a .config file (first argument) and put the resulting options in a -# hash which is returned. This subroutine should be called in a hash +# hash, which is returned. This subroutine should be called in a hash # context or it will not be very useful. -sub process_config ($) +sub process_config($) { my $filename = shift; my %conf; @@ -29,11 +30,12 @@ sub process_config ($) open $in, $filename or die "File not found: $filename"; while (<$in>) { if (/^CONFIG_(\w+)\s*=\s*(\S.*?)\s*$/) { - $conf{$1} = $2; + my $c = \($conf{$1} = $2); + $$c =~ y/nmy/012/ if $$c =~ /^.$/; next; } if (/^# CONFIG_(\w+) is not set$/) { - $conf{$1} = 'n'; + $conf{$1} = 0; next; } unless (/^#|$/) { @@ -49,10 +51,8 @@ sub add_bool($) my $arg=shift; exists $config{$arg} or die "Adding unknown boolean '$arg'"; - $tristate{$arg}="bool"; - printf "Boolean:%s\n",$arg if $debug; - - $kernopts{$arg}='y'; + print "Boolean: $arg\n" if $debug; + $tristate{$arg} = "bool"; } sub add_tristate($) @@ -60,9 +60,10 @@ sub add_tristate($) my $arg=shift; exists $config{$arg} or die "Adding unknown tristate '$arg'"; + print "Tristate: $arg\n" if $debug; $tristate{$arg}="tristate"; - - $kernopts{$arg}='m'; + # tri default is 'm' + $config{$arg} = 1 if($config{$arg}); } sub add_int($) @@ -96,18 +97,17 @@ sub set_hex_value($$) my $val = shift; exists $hexopt{$key} or die "Default for unknown hex option '$key'"; - $hexopt{$key} = "0x".$val; + $hexopt{$key} = "0x$val"; } sub add_config($) { - my $arg=shift; + my $arg = shift; - if ($arg =~ m/^(\w+)/) { - # Have option default to 'on' - $config{$1} = 1; + if ($arg =~ /^(\w+)\s*$/) { + $config{$1} = 2; } else { - die "Do not understand config variable '$arg'"; + die "Do not understand config variable '$arg'"; } } @@ -120,90 +120,172 @@ sub disable_config($) $config{$key} = 0 if (exists $config{$key}); } -################################################################# -# Make a list of dependencies and the number of references for it -sub check_deps($$) +# %{$depend{'FOO'}} lists all variables which depend on FOO. This is the +# reverse of the variables that FOO depends on. +my %depend = (); +sub finddeps($$) { - my $key=shift; - my $arg=shift; - - if ($depmods{$key}) { - $depmods{$key}=$depmods{$key}." $arg"; - } else { - $depmods{$key}=$arg; - } - $arg=$arg." "; - - while ($arg ne "") { - if ($arg =~ m/^([A-Z0-9_]+) /) { - my $val=$1; - my $prev=$depend{$val}; - $depend { $val } = 1+$prev; - } - $arg =~ s/^[^ ]+[ ]+//; - } + my $key = shift; + my $deps = shift; - return $ok; + $deps =~ s/^\W+//; + $depend{$_}{$key} = 1 foreach(split(/\W[\Wynm]*/, $deps)); } -###################################################### -# Checks if all dependencies for the key are satisfied -sub deps_ok($) +# @{$depends{'FOO'}} is a list of dependency expressions that FOO depends +# on. This is the reverse of the variables that depend on FOO. +my %depends = (); +sub depends($$) { - my $key=shift; - my $arg=$depmods{$key}; - my $ok=1; + my $key = shift; + my $deps = shift; - if ($arg eq "") { - return $ok; + if(!defined $key || $key eq '') { + print "Got bad key with $deps\n"; + return; } + finddeps($key, $deps); + push @{$depends{$key}}, $deps; +} - $arg=$arg." "; - - - printf "$key: deps are '$arg'\n" if $debug; +sub selects($$$) +{ + my $key = shift; + my $select = shift; + my $if = shift; + + finddeps($key, $select); + if(defined $if) { + finddeps($key, $if); + # Transform "select X if Y" into "depends on !Y || X" + $select = "!($if) || ($select)"; + } + push @{$depends{$key}}, $select; +} - while ($arg ne "") { - if ($arg =~ m/^([A-Z0-9_]+) /) { - if ((! exists $kernopts {$1}) || ($kernopts {$1} eq 'n')) { - printf "$key: Required kernel opt '$1' is not present\n"; - $ok=0; +# Needs: +# %depend <- %depend{FOO} lists the variables that depend on FOO +# %depends <- %depends{FOO} lists the dependency expressions for FOO +# %config <- the value of all media variables +# %kernopts <- the value of all kernel variables (including media ones) +# +# Checks the dependencies of all media variables, recursively. Returns +# a new hash that has the new values of all media variables. +sub checkdeps() +{ + my %allconfig; + + @allconfig{keys %depend} = @kernopts{keys %depend}; + @allconfig{keys %config} = values %config; + # Set undef values to 0 + map { defined $_ or $_ = 0 } values %allconfig; + + # First run, check deps for all the v4l-dvb variables. Following + # runs, check all variables which depend on a variable that was + # changed. Stop when no more variables change. + for(my %changed = (), my @tocheck = keys %config; @tocheck; + @tocheck = keys %changed, %changed = ()) { + foreach (@tocheck) { + next unless($allconfig{$_}); # skip disabled vars + if (!checkvardeps($_)) { + $changed{$_} = 1 foreach keys %{$depend{$_}}; } } - if ($arg =~ m/^\!([A-Z0-9_]+) /) { - if ($kernopts {$1} eq 'y') { - printf "$key: Driver is incompatible with '$1'\n"; - $ok=0; + } + return map { $_ => $allconfig{$_} } keys %config; + + # Check the dependencies of a variable, if one fails the variable + # is set to 0. Returns 0 if the variable failed, 1 if it passed. + sub checkvardeps($) { + my $key = shift; + my $deps = $depends{$key}; + foreach (@$deps) { + if (!eval(toperl($_))) { + $allconfig{$key} = 0; + return 0; } } - $arg =~ s/^[^ ]+ //; + return 1; } - return $ok; + # Convert a Kconfig expression to a Perl expression + sub toperl($) + { + $_ = shift; + + # Turn n,m,y into 0,1,2 + s/\bn\b/0/g; s/\bm\b/1/g; s/\by\b/2/g; + + # Turn = into ==, but keep != as != (ie. not !==) + s/(?<!!)=/==/g; + + # Turn FOO into the value of $allconfig{FOO} + s/\b([A-Za-z_]\w*)\b/$allconfig{$1}/g; + + return $_; + } } -# List of all kconfig files read in, could be used to make dependencies -# for the output combined Kconfig file. -my @kconfigfiles = (); +# Text to be added to disabled options +my $disabled_msg = <<'EOF'; + ---help--- + WARNING! This driver needs at least kernel %s! It may not + compile or work correctly on your kernel, which is too old. -# Read and parse a Kconfig file. First base of source directory tree the -# second is the file (with path). Recursivly parses Kconfig files from -# 'source' directives. +EOF + +# List of all kconfig files read in, used to make dependencies for the +# output combined Kconfig file. +my @kconfigfiles = (); +# Read and parse a Kconfig file. First argument is base of source +# directory tree, the second is the file to open (with path). Recursivly +# parses Kconfig files from 'source' directives. +# # Prints to OUT a combined version of all the Kconfig files. This file # is edited slightly to disable options that need a newer kernel. sub open_kconfig($$) { my ($dir,$file)=@_; my $in = new FileHandle; - my $disabled=0; my $key; + my $disabled = 0; + my $in_help = 0; + my $default_seen = 0; print "Opening $file\n" if $debug; - open $in, "$file" or die "File not found: $file"; + open $in, '<', $file or die "File not found: $file"; push @kconfigfiles, $file; while (<$in>) { + # In our Kconfig files, the first non-help line after the + # help text always has no indention. Technically, the + # help text is ended by just by the indention decreasing, + # but that is a pain to keep track of. + if ($in_help && /^\S/) { + $in_help = 0; + } elsif ($in_help) { + # Still inside help text + next; + } + + # Start of help text + if (/^\s*(---)?help(---)?\s*$/) { + $in_help = 1; + # Insert VIDEO_KERNEL_VERSION dependency, default + # n line, and help text note for disabled drivers. + if ($disabled) { + if(exists $tristate{$key} && !$default_seen) { + print OUT "\tdefault n\n"; + } + print OUT "\tdepends on VIDEO_KERNEL_VERSION\n"; + $_ = sprintf($disabled_msg, $minver{$key}); + } + next; + } + # No help text should get processed past this point + $in_help and die "I'm very confused"; + # start of a new stanza, reset - if (m/^\w/) { + if (/^\w/) { $disabled = 0; $default_seen = 0; $key = undef; @@ -211,78 +293,60 @@ sub open_kconfig($$) { if (m|^\s*source\s+"([^"]+)"\s*$| || m|^\s*source\s+(\S+)\s*$|) { - open_kconfig($dir,"$dir/$1"); + open_kconfig($dir, "$dir/$1"); + $_ = ''; # don't print the source line itself next; } - if (m|^\s+depends on\s+(.+?)\s*$|) { - check_deps ($key,$1); - } - # If a "select" dependency is not satisfied, that - # dependency is broken - if (m|^\s+select\s+(.+?)\s*(if .*?)?\s*$|) { - check_deps ($key,$1); - } - if (m|^\s+bool(ean)?\s|) { - add_bool($key); - } - if (m|^\s+tristate\s|) { - add_tristate($key); - } - if (m|^\s+int\s|) { - add_int($key); - } - if (m|^\s+hex\s|) { - add_hex($key); + + if (m|^\s*config (\w+)\s*$|) { + $key = $1; + add_config($key); + + if (exists $minver{$key} && + cmp_ver($minver{$key}, $kernver) > 0) { + $disabled = 1; + disable_config($key); + print "$key: Requires at least kernel $minver{$key}\n"; + print OUT "# $key disabled for insufficient kernel version\n"; + } else { + $disabled=0; + } + } elsif (m|^\s*comment\s+"[^"]*"\s*$|) { + $key = 'comment'; + } elsif (m|^\s*menu\s+"[^"]*"\s*$|) { + $key = 'menu'; } + + # Don't process any directives in comment blocks (or menus) + next if ($key eq 'comment' || $key eq 'menu'); + + add_bool($key) if(/^\s*bool(ean)?\s/); + add_tristate($key) if (/^\s*tristate\s/); + add_int($key) if (/^\s*int\s/); + add_hex($key) if (/^\s*hex\s/); + + depends($key, $1) if (m|^\s*depends on\s+(.+?)\s*$|); + selects($key, $1, $3) if (m|^\s*select\s+(\w+)(\s+if\s+(.+?))?\s*$|); + # Get default for int options - if (m|^\s+default "(\d+)"| && exists $intopt{$key}) { + if (m|^\s*default "(\d+)"| && exists $intopt{$key}) { set_int_value($key, $1); + next; } # Get default for hex options - if (m|^\s+default "(0x)?([[:xdigit:]]+)"| && exists $hexopt{$key}) { + if (m|^\s*default "(0x)?([[:xdigit:]]+)"| && exists $hexopt{$key}) { set_hex_value($key, $2); + next; } # Override default for disabled tri/bool options - if (m/^\s+default (y|n|m|"yes"|"no")\s+(if .*)?$/ && + # We don't care about the default for tri/bool options otherwise + if (m/^\s*default (y|n|m|"yes"|"no")(\s+if .*)?\s*$/ && exists $tristate{$key} && $disabled) { $default_seen = 1; $_ = "\tdefault n\n"; - } - # check for end of config definition for disabled drivers - # we need to make sure we've disabled it, and add a bit - # to the help text - if (m|^\s*(---)?help(---)?\s*$| && $disabled) { - if(exists $tristate{$key} && !$default_seen) { - print OUT "\tdefault n\n"; - } - print OUT <<"EOF"; - depends on VIDEO_KERNEL_VERSION - help - WARNING! This driver needs at least kernel $minver{$key}! It may not - compile or work correctly on your kernel, which is too old. - -EOF next; } - - if (m|^\s*config (\w+)\s*$|) { - $key=$1; - add_config ($1); - - if (exists $minver{$key} && - cmp_ver($minver{$key}, $kernver) > 0) { - $disabled=1; - disable_config ($key); - print "$key requires version $minver{$key}\n"; - print OUT "# $key disabled for insufficient kernel version\n"; - } else { - printf "OK: $key requires version %s\n", exists $minver{$key}?$minver{$key}:"any" if $debug; - $disabled=0; - } - } - - s/^main(menu\s\"[^\"]+)/\1 - DON'T CHANGE IT!/; - + } continue { print OUT $_; } close $in; @@ -293,7 +357,7 @@ sub parse_versions() my $in = new FileHandle; my $ver; - open $in, "versions.txt" or die "File not found: versions.txt"; + open $in, '<versions.txt' or die "File not found: versions.txt"; while (<$in>) { if (/\[(\d+\.\d+\.\d+)\]/) { $ver = $1; @@ -335,9 +399,23 @@ sub cmp_ver($$) return $v1_sublevel <=> $v2_sublevel; } -# Get kernel's config settings +# Get Kernel's config settings %kernopts = process_config("$kernel/.config"); +# Modules must be on, or building out of tree drivers makes no sense +if(!$kernopts{MODULES}) { + print <<"EOF"; +You appear to have loadable modules turned off in your kernel. You can +not compile the v4l-dvb drivers, as modules, and use them with a kernel +that has modules disabled. + +If you want to compile these drivers into your kernel, you should +use 'make kernel-links' to link the source for these drivers into +your kernel tree. Then configure and compile the kernel. +EOF + exit -1; +} + # Get minimum kernel version for our variables parse_versions(); @@ -346,11 +424,13 @@ get_version(); print "Preparing to compile for kernel version $kernver\n"; -open OUT,">Kconfig" or die "Cannot write Kconfig file"; +kernelcheck(); +open OUT, ">Kconfig" or die "Cannot write Kconfig file"; print OUT <<"EOF"; mainmenu "V4L/DVB menu" source Kconfig.kern +source Kconfig.sound config VIDEO_KERNEL_VERSION bool "Enable drivers not supported by this kernel" default n @@ -372,44 +452,67 @@ config VIDEO_KERNEL_VERSION EOF -open_kconfig ("../linux","../linux/drivers/media/Kconfig"); -open_kconfig (".","./Kconfig.sound"); - -print OUT "source Kconfig.sound\n"; +open_kconfig('../linux', '../linux/drivers/media/Kconfig'); +open_kconfig('.', './Kconfig.sound'); close OUT; -# Create make dependency rule for the Kconfig -open OUT, '>.kconfig.dep' or die "Cannot write .kconfig.dep"; -print OUT "Kconfig: "; -print OUT join(" \\\n\t", @kconfigfiles), "\n"; -close OUT; +# These options should default to off +disable_config('DVB_AV7110_FIRMWARE'); +disable_config('DVB_CINERGYT2_TUNING'); +disable_config('DVB_FE_CUSTOMISE'); -while ( my ($key, $value) = each(%config) ) { - delete $depend{$key}; -} +# Check dependencies +my %newconfig = checkdeps(); -open OUT,">Kconfig.kern" or die "Cannot write Kconfig.kern file"; +# TODO: tell the user which options were disabled at this point +%config = %newconfig; -while ( my ($key, $value) = each(%depend) ) { - if ($kernopts{$key}) { - print OUT "# $key with $value refs\nconfig $key\n\ttristate\n\tdefault ". - $kernopts{$key}."\n\n"; - } else { - print OUT "# $key with $value refs\nconfig $key\n\ttristate\n\tdefault n #not found\n\n"; - } +# Create Kconfig.kern, listing all non-media (i.e. kernel) variables +# that something depended on. +$depend{MODULES}{always} = 1; # Make sure MODULES will appear +open OUT, '>Kconfig.kern' or die "Cannot write Kconfig.kern file: $!"; +while (my ($key, $deps) = each %depend) { + next if exists $config{$key}; # Skip media variables + + print OUT "# Needed by ", join(', ', keys %$deps), "\n"; + print OUT "config $key\n\ttristate\n"; + print OUT "\tdefault ", qw(n m y)[$kernopts{$key}], "\n\n"; } close OUT; -# These options should default to off -disable_config('DVB_AV7110_FIRMWARE'); -disable_config('DVB_CINERGYT2_TUNING'); -disable_config('DVB_FE_CUSTOMISE'); +# Create make dependency rules for the Kconfig file +open OUT, '>.kconfig.dep' or die "Cannot write .kconfig.dep file: $!"; +print OUT 'Kconfig: '; +print OUT join(" \\\n\t", @kconfigfiles), "\n"; +close OUT; -# Hack for check sound/oss/aci.h header +# Produce a .config file if forced or one doesn't already exist +if ($force_kconfig==1 || !-e '.config') { + open OUT, '>.config' or die "Cannot write .config file: $!"; + foreach (keys %tristate) { + if ($config{$_}) { + print OUT "CONFIG_$_=", qw(n m y)[$config{$_}], "\n"; + } else { + print OUT "# CONFIG_$_ is not set\n"; + } + } + while (my ($key,$value) = each %intopt) { + print OUT "CONFIG_$key=$value\n" if($config{$key}); + } + while (my ($key,$value) = each %hexopt) { + print OUT "CONFIG_$key=$value\n" if($config{$key}); + } + close OUT; + print "Created default (all yes) .config file\n"; +} + +# Check for full kernel sources and print a warning +sub kernelcheck() +{ + my $fullkernel="$kernel/fs/fcntl.c"; + if (! -e $fullkernel) { + print <<"EOF2"; -my $fullkernel="$kernel/fs/fcntl.c"; -if (! -e $fullkernel) { - print <<"EOF2"; ***WARNING:*** You do not have the full kernel sources installed. This does not prevent you from building the v4l-dvb tree if you have the kernel headers, but the full kernel source may be required in order to use @@ -428,45 +531,5 @@ make all modules_install install Please see your distro's web site for instructions to build a new kernel. EOF2 -} - -# Recursively check for broken dependencies -my $i; -do { - $i=0; - while ( my ($key,$value) = each(%kernopts) ) { - if ($value ne 'n') { - if (!deps_ok($key)) { - $kernopts{$key}='n'; - } - $i=$i+1; - } } -} until (!$disable); - -# Produce a .config file if it's forced or one doesn't already exist -if (($force_kconfig eq 1) || !open IN,".config") { - open OUT,">.config" or die "Cannot write .config file"; - while ( my ($key,$value) = each(%tristate) ) { - if (!$config{$key}) { - print OUT "# CONFIG_$key is not set\n"; - } elsif ($kernopts{$key}) { - if ($kernopts{$key} eq 'n') { - print OUT "# CONFIG_$key is not set\n"; - } else { - print OUT "CONFIG_$key=".$kernopts{$key}."\n"; - } - } elsif ($value eq 'tristate') { - print OUT "CONFIG_$key=m\n"; - } else { # must be 'bool' - print OUT "CONFIG_$key=y\n"; - } - } - while ( my ($key,$value) = each(%intopt) ) { - print OUT "CONFIG_$key=$value\n"; - } - while ( my ($key,$value) = each(%hexopt) ) { - print OUT "CONFIG_$key=$value\n"; - } - close OUT; } |