3 # Original version were part of Gerd Knorr's v4l scripts.
5 # Several improvements by (c) 2005-2007 Mauro Carvalho Chehab
7 # Largely re-written (C) 2007 Trent Piepho <xyzzy@speakeasy.org>
8 # Stolen for DRM usage by airlied
12 # This acts as a sort of mini version of cpp, which will process
13 # #if/#elif/#ifdef/etc directives to strip out code used to support
14 # multiple kernel versions or otherwise not wanted to be sent upstream to
17 # Conditional compilation directives fall into two catagories,
18 # "processed" and "other". The "other" directives are ignored and simply
19 # output as they come in without changes (see 'keep' exception). The
20 # "processed" variaty are evaluated and only the lines in the 'true' part
21 # are kept, like cpp would do.
23 # If gentree knows the result of an expression, that directive will be
24 # "processed", otherwise it will be an "other". gentree knows the value
25 # of LINUX_VERSION_CODE, BTTV_VERSION_CODE, the KERNEL_VERSION(x,y,z)
26 # macro, numeric constants like 0 and 1, and a few defines like MM_KERNEL
29 # An exception is if the comment "/*KEEP*/" appears after the expression,
30 # in which case that directive will be considered an "other" and not
31 # processed, other than to remove the keep comment.
34 # don't specify the root directory e.g. '/' or even '////'
35 # directives continued with a back-slash will always be ignored
36 # you can't modify a source tree in-place, i.e. source dir == dest dir
46 if (!defined($DESTDIR)) {
47 print "Usage:\ngentree.pl\t<version> <source dir> <dest dir>\n\n";
51 my $BTTVCODE = KERNEL_VERSION
(0,9,17);
52 my ($LINUXCODE, $extra) = kernel_version
($VERSION);
56 'LINUX_VERSION_CODE' => $LINUXCODE,
57 'MM_KERNEL' => ($extra =~ /-mm/)?
1:0,
58 'DRM_ODD_MM_COMPAT' => 0,
59 'I915_HAVE_FENCE' => 1,
60 'I915_HAVE_BUFFER' => 1,
61 'VIA_HAVE_DMABLIT' => 1,
62 'VIA_HAVE_CORE_MM' => 1,
63 'VIA_HAVE_FENCE' => 1,
64 'VIA_HAVE_BUFFER' => 1,
65 'SIS_HAVE_CORE_MM' => 1,
66 'DRM_FULL_MM_COMPAT' => 1,
70 #################################################################
73 sub kernel_version
($) {
74 $_[0] =~ m/(\d+)\.(\d+)\.(\d+)(.*)/;
75 return ($1*65536 + $2*256 + $3, $4);
79 sub KERNEL_VERSION
($$$) { return $_[0]*65536 + $_[1]*256 + $_[2]; }
83 s
|/\*.*?\*/||go
; # delete /* */ comments
84 s
|//.*$||o
; # delete // comments
85 s/\bdefined\s*\(/(/go; # defined(foo) to (foo)
86 while (/\b([_A-Za-z]\w*)\b/go) {
87 if (exists $defs{$1}) {
88 my $id = $1; my $pos = $-[0];
91 } elsif ($1 ne 'KERNEL_VERSION') {
95 return(eval($_) ?
1 : 0);
98 #################################################################
99 # filter out version-specific code
101 sub filter_source
($$) {
108 my @dbgargs = \
($level, %state, %if, $line);
110 my $level = ${$_[1][0]};
111 printf STDERR
("/* BP %4d $_[0] state=$_[1][1]->{$level} if=$_[1][2]->{$level} level=$level (${$_[1][3]}) */\n", $.) if $DEBUG;
114 open IN
, '<', $in or die "Error opening $in: $!\n";
115 open OUT
, '>', $out or die "Error opening $out: $!\n";
117 print STDERR
"File: $in, for kernel $VERSION($LINUXCODE)/\n" if $DEBUG;
119 while ($line = <IN
>) {
121 next if ($line =~ m/^#include \"compat.h\"/o);
122 # next if ($line =~ m/[\$]Id:/);
124 # For "#if 0 /*KEEP*/;" the ; should be dropped too
125 if ($line =~ m@
^\s
*#\s*if(n?def)?\s.*?(\s*/\*\s*(?i)keep\s*\*/;?)@) {
126 $state{$level} = "ifother";
128 dbgline
"#if$1 (keep)", @dbgargs;
132 # handle all ifdef/ifndef lines
133 elsif ($line =~ /^\s*#\s*if(n?)def\s*(\w+)/o) {
134 if (exists $defs{$2}) {
135 $state{$level} = 'if';
136 $if{$level} = ($1 eq 'n') ?
!$defs{$2} : $defs{$2};
137 dbgline
"#if$1def $2", @dbgargs;
141 $state{$level} = "ifother";
143 dbgline
"#if$1def (other)", @dbgargs;
147 elsif ($line =~ /^\s*#\s*if\s+(.*)$/o) {
148 my $res = evalexp
($1);
150 $state{$level} = 'if';
152 dbgline
'#if '.($res?
'(yes)':'(no)'), @dbgargs;
156 $state{$level} = 'ifother';
158 dbgline
'#if (other)', @dbgargs;
163 elsif ($line =~ /^\s*#\s*elif\s+(.*)$/o) {
166 $level < 0 and die "more elifs than ifs";
167 $state{$level} =~ /if/ or die "unmatched elif";
169 if ($state{$level} eq 'if' && !$if{$level}) {
170 my $res = evalexp
($exp);
171 defined $res or die 'moving from if to ifother';
172 $state{$level} = 'if';
174 dbgline
'#elif1 '.($res?
'(yes)':'(no)'), @dbgargs;
177 } elsif ($state{$level} ne 'ifother') {
179 $state{$level} = 'elif';
180 dbgline
'#elif0', @dbgargs;
186 elsif ($line =~ /^\s*#\s*else/o) {
188 $level < 0 and die "more elses than ifs";
189 $state{$level} =~ /if/ or die "unmatched else";
190 $if{$level} = !$if{$level} if ($state{$level} eq 'if');
191 $state{$level} =~ s/^if/else/o; # if -> else, ifother -> elseother, elif -> elif
192 dbgline
'#else', @dbgargs;
194 next if $state{$level-1} !~ /other$/o;
196 elsif ($line =~ /^\s*#\s*endif/o) {
198 $level < 0 and die "more endifs than ifs";
199 dbgline
'#endif', @dbgargs;
200 next if $state{$level} !~ /other$/o;
204 for (my $i=0;$i<$level;$i++) {
205 next if $state{$i} =~ /other$/o; # keep code in ifother/elseother blocks
208 dbgline
'DEL', @
{[\
$i, \
%state, \
%if, \
$line]};
212 print OUT
"$line\n" if $print;
218 #################################################################
221 my $file = $File::Find
::name
;
223 return if ($file =~ /CVS/);
224 return if ($file =~ /~$/);
227 $f2 =~ s/^\Q$SRC\E/$DESTDIR/;
229 my $mode = (stat($file))[2];
230 if ($mode & S_IFDIR
) {
231 print("mkdir -p '$f2'\n");
232 system("mkdir -p '$f2'"); # should check for error
235 print "from $file to $f2\n";
237 if ($file =~ m/.*\.[ch]$/) {
238 filter_source
($file, $f2);
240 system("cp $file $f2");
247 printf "kernel is %s (0x%x)\n",$VERSION,$LINUXCODE;
249 # remove any trailing slashes from dir names. don't pass in just '/'
250 $SRC =~ s
|/*$||; $DESTDIR =~ s|/*$||;
252 print "finding files at $SRC\n";
254 find
({wanted
=> \
&parse_dir
, no_chdir
=> 1}, $SRC);