1*4882a593Smuzhiyun#!/usr/bin/env perl 2*4882a593Smuzhiyunuse strict; 3*4882a593Smuzhiyunuse Text::Tabs; 4*4882a593Smuzhiyunuse Getopt::Long; 5*4882a593Smuzhiyunuse Pod::Usage; 6*4882a593Smuzhiyun 7*4882a593Smuzhiyunmy $debug; 8*4882a593Smuzhiyunmy $help; 9*4882a593Smuzhiyunmy $man; 10*4882a593Smuzhiyun 11*4882a593SmuzhiyunGetOptions( 12*4882a593Smuzhiyun "debug" => \$debug, 13*4882a593Smuzhiyun 'usage|?' => \$help, 14*4882a593Smuzhiyun 'help' => \$man 15*4882a593Smuzhiyun) or pod2usage(2); 16*4882a593Smuzhiyun 17*4882a593Smuzhiyunpod2usage(1) if $help; 18*4882a593Smuzhiyunpod2usage(-exitstatus => 0, -verbose => 2) if $man; 19*4882a593Smuzhiyunpod2usage(2) if (scalar @ARGV < 2 || scalar @ARGV > 3); 20*4882a593Smuzhiyun 21*4882a593Smuzhiyunmy ($file_in, $file_out, $file_exceptions) = @ARGV; 22*4882a593Smuzhiyun 23*4882a593Smuzhiyunmy $data; 24*4882a593Smuzhiyunmy %ioctls; 25*4882a593Smuzhiyunmy %defines; 26*4882a593Smuzhiyunmy %typedefs; 27*4882a593Smuzhiyunmy %enums; 28*4882a593Smuzhiyunmy %enum_symbols; 29*4882a593Smuzhiyunmy %structs; 30*4882a593Smuzhiyun 31*4882a593Smuzhiyunrequire Data::Dumper if ($debug); 32*4882a593Smuzhiyun 33*4882a593Smuzhiyun# 34*4882a593Smuzhiyun# read the file and get identifiers 35*4882a593Smuzhiyun# 36*4882a593Smuzhiyun 37*4882a593Smuzhiyunmy $is_enum = 0; 38*4882a593Smuzhiyunmy $is_comment = 0; 39*4882a593Smuzhiyunopen IN, $file_in or die "Can't open $file_in"; 40*4882a593Smuzhiyunwhile (<IN>) { 41*4882a593Smuzhiyun $data .= $_; 42*4882a593Smuzhiyun 43*4882a593Smuzhiyun my $ln = $_; 44*4882a593Smuzhiyun if (!$is_comment) { 45*4882a593Smuzhiyun $ln =~ s,/\*.*(\*/),,g; 46*4882a593Smuzhiyun 47*4882a593Smuzhiyun $is_comment = 1 if ($ln =~ s,/\*.*,,); 48*4882a593Smuzhiyun } else { 49*4882a593Smuzhiyun if ($ln =~ s,^(.*\*/),,) { 50*4882a593Smuzhiyun $is_comment = 0; 51*4882a593Smuzhiyun } else { 52*4882a593Smuzhiyun next; 53*4882a593Smuzhiyun } 54*4882a593Smuzhiyun } 55*4882a593Smuzhiyun 56*4882a593Smuzhiyun if ($is_enum && $ln =~ m/^\s*([_\w][\w\d_]+)\s*[\,=]?/) { 57*4882a593Smuzhiyun my $s = $1; 58*4882a593Smuzhiyun my $n = $1; 59*4882a593Smuzhiyun $n =~ tr/A-Z/a-z/; 60*4882a593Smuzhiyun $n =~ tr/_/-/; 61*4882a593Smuzhiyun 62*4882a593Smuzhiyun $enum_symbols{$s} = "\\ :ref:`$s <$n>`\\ "; 63*4882a593Smuzhiyun 64*4882a593Smuzhiyun $is_enum = 0 if ($is_enum && m/\}/); 65*4882a593Smuzhiyun next; 66*4882a593Smuzhiyun } 67*4882a593Smuzhiyun $is_enum = 0 if ($is_enum && m/\}/); 68*4882a593Smuzhiyun 69*4882a593Smuzhiyun if ($ln =~ m/^\s*#\s*define\s+([_\w][\w\d_]+)\s+_IO/) { 70*4882a593Smuzhiyun my $s = $1; 71*4882a593Smuzhiyun my $n = $1; 72*4882a593Smuzhiyun $n =~ tr/A-Z/a-z/; 73*4882a593Smuzhiyun 74*4882a593Smuzhiyun $ioctls{$s} = "\\ :ref:`$s <$n>`\\ "; 75*4882a593Smuzhiyun next; 76*4882a593Smuzhiyun } 77*4882a593Smuzhiyun 78*4882a593Smuzhiyun if ($ln =~ m/^\s*#\s*define\s+([_\w][\w\d_]+)\s+/) { 79*4882a593Smuzhiyun my $s = $1; 80*4882a593Smuzhiyun my $n = $1; 81*4882a593Smuzhiyun $n =~ tr/A-Z/a-z/; 82*4882a593Smuzhiyun $n =~ tr/_/-/; 83*4882a593Smuzhiyun 84*4882a593Smuzhiyun $defines{$s} = "\\ :ref:`$s <$n>`\\ "; 85*4882a593Smuzhiyun next; 86*4882a593Smuzhiyun } 87*4882a593Smuzhiyun 88*4882a593Smuzhiyun if ($ln =~ m/^\s*typedef\s+([_\w][\w\d_]+)\s+(.*)\s+([_\w][\w\d_]+);/) { 89*4882a593Smuzhiyun my $s = $2; 90*4882a593Smuzhiyun my $n = $3; 91*4882a593Smuzhiyun 92*4882a593Smuzhiyun $typedefs{$n} = "\\ :c:type:`$n <$s>`\\ "; 93*4882a593Smuzhiyun next; 94*4882a593Smuzhiyun } 95*4882a593Smuzhiyun if ($ln =~ m/^\s*enum\s+([_\w][\w\d_]+)\s+\{/ 96*4882a593Smuzhiyun || $ln =~ m/^\s*enum\s+([_\w][\w\d_]+)$/ 97*4882a593Smuzhiyun || $ln =~ m/^\s*typedef\s*enum\s+([_\w][\w\d_]+)\s+\{/ 98*4882a593Smuzhiyun || $ln =~ m/^\s*typedef\s*enum\s+([_\w][\w\d_]+)$/) { 99*4882a593Smuzhiyun my $s = $1; 100*4882a593Smuzhiyun 101*4882a593Smuzhiyun $enums{$s} = "enum :c:type:`$s`\\ "; 102*4882a593Smuzhiyun 103*4882a593Smuzhiyun $is_enum = $1; 104*4882a593Smuzhiyun next; 105*4882a593Smuzhiyun } 106*4882a593Smuzhiyun if ($ln =~ m/^\s*struct\s+([_\w][\w\d_]+)\s+\{/ 107*4882a593Smuzhiyun || $ln =~ m/^\s*struct\s+([[_\w][\w\d_]+)$/ 108*4882a593Smuzhiyun || $ln =~ m/^\s*typedef\s*struct\s+([_\w][\w\d_]+)\s+\{/ 109*4882a593Smuzhiyun || $ln =~ m/^\s*typedef\s*struct\s+([[_\w][\w\d_]+)$/ 110*4882a593Smuzhiyun ) { 111*4882a593Smuzhiyun my $s = $1; 112*4882a593Smuzhiyun 113*4882a593Smuzhiyun $structs{$s} = "struct $s\\ "; 114*4882a593Smuzhiyun next; 115*4882a593Smuzhiyun } 116*4882a593Smuzhiyun} 117*4882a593Smuzhiyunclose IN; 118*4882a593Smuzhiyun 119*4882a593Smuzhiyun# 120*4882a593Smuzhiyun# Handle multi-line typedefs 121*4882a593Smuzhiyun# 122*4882a593Smuzhiyun 123*4882a593Smuzhiyunmy @matches = ($data =~ m/typedef\s+struct\s+\S+?\s*\{[^\}]+\}\s*(\S+)\s*\;/g, 124*4882a593Smuzhiyun $data =~ m/typedef\s+enum\s+\S+?\s*\{[^\}]+\}\s*(\S+)\s*\;/g,); 125*4882a593Smuzhiyunforeach my $m (@matches) { 126*4882a593Smuzhiyun my $s = $m; 127*4882a593Smuzhiyun 128*4882a593Smuzhiyun $typedefs{$s} = "\\ :c:type:`$s`\\ "; 129*4882a593Smuzhiyun next; 130*4882a593Smuzhiyun} 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun# 133*4882a593Smuzhiyun# Handle exceptions, if any 134*4882a593Smuzhiyun# 135*4882a593Smuzhiyun 136*4882a593Smuzhiyunmy %def_reftype = ( 137*4882a593Smuzhiyun "ioctl" => ":ref", 138*4882a593Smuzhiyun "define" => ":ref", 139*4882a593Smuzhiyun "symbol" => ":ref", 140*4882a593Smuzhiyun "typedef" => ":c:type", 141*4882a593Smuzhiyun "enum" => ":c:type", 142*4882a593Smuzhiyun "struct" => ":c:type", 143*4882a593Smuzhiyun); 144*4882a593Smuzhiyun 145*4882a593Smuzhiyunif ($file_exceptions) { 146*4882a593Smuzhiyun open IN, $file_exceptions or die "Can't read $file_exceptions"; 147*4882a593Smuzhiyun while (<IN>) { 148*4882a593Smuzhiyun next if (m/^\s*$/ || m/^\s*#/); 149*4882a593Smuzhiyun 150*4882a593Smuzhiyun # Parsers to ignore a symbol 151*4882a593Smuzhiyun 152*4882a593Smuzhiyun if (m/^ignore\s+ioctl\s+(\S+)/) { 153*4882a593Smuzhiyun delete $ioctls{$1} if (exists($ioctls{$1})); 154*4882a593Smuzhiyun next; 155*4882a593Smuzhiyun } 156*4882a593Smuzhiyun if (m/^ignore\s+define\s+(\S+)/) { 157*4882a593Smuzhiyun delete $defines{$1} if (exists($defines{$1})); 158*4882a593Smuzhiyun next; 159*4882a593Smuzhiyun } 160*4882a593Smuzhiyun if (m/^ignore\s+typedef\s+(\S+)/) { 161*4882a593Smuzhiyun delete $typedefs{$1} if (exists($typedefs{$1})); 162*4882a593Smuzhiyun next; 163*4882a593Smuzhiyun } 164*4882a593Smuzhiyun if (m/^ignore\s+enum\s+(\S+)/) { 165*4882a593Smuzhiyun delete $enums{$1} if (exists($enums{$1})); 166*4882a593Smuzhiyun next; 167*4882a593Smuzhiyun } 168*4882a593Smuzhiyun if (m/^ignore\s+struct\s+(\S+)/) { 169*4882a593Smuzhiyun delete $structs{$1} if (exists($structs{$1})); 170*4882a593Smuzhiyun next; 171*4882a593Smuzhiyun } 172*4882a593Smuzhiyun if (m/^ignore\s+symbol\s+(\S+)/) { 173*4882a593Smuzhiyun delete $enum_symbols{$1} if (exists($enum_symbols{$1})); 174*4882a593Smuzhiyun next; 175*4882a593Smuzhiyun } 176*4882a593Smuzhiyun 177*4882a593Smuzhiyun # Parsers to replace a symbol 178*4882a593Smuzhiyun my ($type, $old, $new, $reftype); 179*4882a593Smuzhiyun 180*4882a593Smuzhiyun if (m/^replace\s+(\S+)\s+(\S+)\s+(\S+)/) { 181*4882a593Smuzhiyun $type = $1; 182*4882a593Smuzhiyun $old = $2; 183*4882a593Smuzhiyun $new = $3; 184*4882a593Smuzhiyun } else { 185*4882a593Smuzhiyun die "Can't parse $file_exceptions: $_"; 186*4882a593Smuzhiyun } 187*4882a593Smuzhiyun 188*4882a593Smuzhiyun if ($new =~ m/^\:c\:(data|func|macro|type)\:\`(.+)\`/) { 189*4882a593Smuzhiyun $reftype = ":c:$1"; 190*4882a593Smuzhiyun $new = $2; 191*4882a593Smuzhiyun } elsif ($new =~ m/\:ref\:\`(.+)\`/) { 192*4882a593Smuzhiyun $reftype = ":ref"; 193*4882a593Smuzhiyun $new = $1; 194*4882a593Smuzhiyun } else { 195*4882a593Smuzhiyun $reftype = $def_reftype{$type}; 196*4882a593Smuzhiyun } 197*4882a593Smuzhiyun $new = "$reftype:`$old <$new>`"; 198*4882a593Smuzhiyun 199*4882a593Smuzhiyun if ($type eq "ioctl") { 200*4882a593Smuzhiyun $ioctls{$old} = $new if (exists($ioctls{$old})); 201*4882a593Smuzhiyun next; 202*4882a593Smuzhiyun } 203*4882a593Smuzhiyun if ($type eq "define") { 204*4882a593Smuzhiyun $defines{$old} = $new if (exists($defines{$old})); 205*4882a593Smuzhiyun next; 206*4882a593Smuzhiyun } 207*4882a593Smuzhiyun if ($type eq "symbol") { 208*4882a593Smuzhiyun $enum_symbols{$old} = $new if (exists($enum_symbols{$old})); 209*4882a593Smuzhiyun next; 210*4882a593Smuzhiyun } 211*4882a593Smuzhiyun if ($type eq "typedef") { 212*4882a593Smuzhiyun $typedefs{$old} = $new if (exists($typedefs{$old})); 213*4882a593Smuzhiyun next; 214*4882a593Smuzhiyun } 215*4882a593Smuzhiyun if ($type eq "enum") { 216*4882a593Smuzhiyun $enums{$old} = $new if (exists($enums{$old})); 217*4882a593Smuzhiyun next; 218*4882a593Smuzhiyun } 219*4882a593Smuzhiyun if ($type eq "struct") { 220*4882a593Smuzhiyun $structs{$old} = $new if (exists($structs{$old})); 221*4882a593Smuzhiyun next; 222*4882a593Smuzhiyun } 223*4882a593Smuzhiyun 224*4882a593Smuzhiyun die "Can't parse $file_exceptions: $_"; 225*4882a593Smuzhiyun } 226*4882a593Smuzhiyun} 227*4882a593Smuzhiyun 228*4882a593Smuzhiyunif ($debug) { 229*4882a593Smuzhiyun print Data::Dumper->Dump([\%ioctls], [qw(*ioctls)]) if (%ioctls); 230*4882a593Smuzhiyun print Data::Dumper->Dump([\%typedefs], [qw(*typedefs)]) if (%typedefs); 231*4882a593Smuzhiyun print Data::Dumper->Dump([\%enums], [qw(*enums)]) if (%enums); 232*4882a593Smuzhiyun print Data::Dumper->Dump([\%structs], [qw(*structs)]) if (%structs); 233*4882a593Smuzhiyun print Data::Dumper->Dump([\%defines], [qw(*defines)]) if (%defines); 234*4882a593Smuzhiyun print Data::Dumper->Dump([\%enum_symbols], [qw(*enum_symbols)]) if (%enum_symbols); 235*4882a593Smuzhiyun} 236*4882a593Smuzhiyun 237*4882a593Smuzhiyun# 238*4882a593Smuzhiyun# Align block 239*4882a593Smuzhiyun# 240*4882a593Smuzhiyun$data = expand($data); 241*4882a593Smuzhiyun$data = " " . $data; 242*4882a593Smuzhiyun$data =~ s/\n/\n /g; 243*4882a593Smuzhiyun$data =~ s/\n\s+$/\n/g; 244*4882a593Smuzhiyun$data =~ s/\n\s+\n/\n\n/g; 245*4882a593Smuzhiyun 246*4882a593Smuzhiyun# 247*4882a593Smuzhiyun# Add escape codes for special characters 248*4882a593Smuzhiyun# 249*4882a593Smuzhiyun$data =~ s,([\_\`\*\<\>\&\\\\:\/\|\%\$\#\{\}\~\^]),\\$1,g; 250*4882a593Smuzhiyun 251*4882a593Smuzhiyun$data =~ s,DEPRECATED,**DEPRECATED**,g; 252*4882a593Smuzhiyun 253*4882a593Smuzhiyun# 254*4882a593Smuzhiyun# Add references 255*4882a593Smuzhiyun# 256*4882a593Smuzhiyun 257*4882a593Smuzhiyunmy $start_delim = "[ \n\t\(\=\*\@]"; 258*4882a593Smuzhiyunmy $end_delim = "(\\s|,|\\\\=|\\\\:|\\;|\\\)|\\}|\\{)"; 259*4882a593Smuzhiyun 260*4882a593Smuzhiyunforeach my $r (keys %ioctls) { 261*4882a593Smuzhiyun my $s = $ioctls{$r}; 262*4882a593Smuzhiyun 263*4882a593Smuzhiyun $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; 264*4882a593Smuzhiyun 265*4882a593Smuzhiyun print "$r -> $s\n" if ($debug); 266*4882a593Smuzhiyun 267*4882a593Smuzhiyun $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; 268*4882a593Smuzhiyun} 269*4882a593Smuzhiyun 270*4882a593Smuzhiyunforeach my $r (keys %defines) { 271*4882a593Smuzhiyun my $s = $defines{$r}; 272*4882a593Smuzhiyun 273*4882a593Smuzhiyun $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; 274*4882a593Smuzhiyun 275*4882a593Smuzhiyun print "$r -> $s\n" if ($debug); 276*4882a593Smuzhiyun 277*4882a593Smuzhiyun $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; 278*4882a593Smuzhiyun} 279*4882a593Smuzhiyun 280*4882a593Smuzhiyunforeach my $r (keys %enum_symbols) { 281*4882a593Smuzhiyun my $s = $enum_symbols{$r}; 282*4882a593Smuzhiyun 283*4882a593Smuzhiyun $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; 284*4882a593Smuzhiyun 285*4882a593Smuzhiyun print "$r -> $s\n" if ($debug); 286*4882a593Smuzhiyun 287*4882a593Smuzhiyun $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; 288*4882a593Smuzhiyun} 289*4882a593Smuzhiyun 290*4882a593Smuzhiyunforeach my $r (keys %enums) { 291*4882a593Smuzhiyun my $s = $enums{$r}; 292*4882a593Smuzhiyun 293*4882a593Smuzhiyun $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; 294*4882a593Smuzhiyun 295*4882a593Smuzhiyun print "$r -> $s\n" if ($debug); 296*4882a593Smuzhiyun 297*4882a593Smuzhiyun $data =~ s/enum\s+($r)$end_delim/$s$2/g; 298*4882a593Smuzhiyun} 299*4882a593Smuzhiyun 300*4882a593Smuzhiyunforeach my $r (keys %structs) { 301*4882a593Smuzhiyun my $s = $structs{$r}; 302*4882a593Smuzhiyun 303*4882a593Smuzhiyun $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; 304*4882a593Smuzhiyun 305*4882a593Smuzhiyun print "$r -> $s\n" if ($debug); 306*4882a593Smuzhiyun 307*4882a593Smuzhiyun $data =~ s/struct\s+($r)$end_delim/$s$2/g; 308*4882a593Smuzhiyun} 309*4882a593Smuzhiyun 310*4882a593Smuzhiyunforeach my $r (keys %typedefs) { 311*4882a593Smuzhiyun my $s = $typedefs{$r}; 312*4882a593Smuzhiyun 313*4882a593Smuzhiyun $r =~ s,([\_\`\*\<\>\&\\\\:\/]),\\\\$1,g; 314*4882a593Smuzhiyun 315*4882a593Smuzhiyun print "$r -> $s\n" if ($debug); 316*4882a593Smuzhiyun $data =~ s/($start_delim)($r)$end_delim/$1$s$3/g; 317*4882a593Smuzhiyun} 318*4882a593Smuzhiyun 319*4882a593Smuzhiyun$data =~ s/\\ ([\n\s])/\1/g; 320*4882a593Smuzhiyun 321*4882a593Smuzhiyun# 322*4882a593Smuzhiyun# Generate output file 323*4882a593Smuzhiyun# 324*4882a593Smuzhiyun 325*4882a593Smuzhiyunmy $title = $file_in; 326*4882a593Smuzhiyun$title =~ s,.*/,,; 327*4882a593Smuzhiyun 328*4882a593Smuzhiyunopen OUT, "> $file_out" or die "Can't open $file_out"; 329*4882a593Smuzhiyunprint OUT ".. -*- coding: utf-8; mode: rst -*-\n\n"; 330*4882a593Smuzhiyunprint OUT "$title\n"; 331*4882a593Smuzhiyunprint OUT "=" x length($title); 332*4882a593Smuzhiyunprint OUT "\n\n.. parsed-literal::\n\n"; 333*4882a593Smuzhiyunprint OUT $data; 334*4882a593Smuzhiyunclose OUT; 335*4882a593Smuzhiyun 336*4882a593Smuzhiyun__END__ 337*4882a593Smuzhiyun 338*4882a593Smuzhiyun=head1 NAME 339*4882a593Smuzhiyun 340*4882a593Smuzhiyunparse_headers.pl - parse a C file, in order to identify functions, structs, 341*4882a593Smuzhiyunenums and defines and create cross-references to a Sphinx book. 342*4882a593Smuzhiyun 343*4882a593Smuzhiyun=head1 SYNOPSIS 344*4882a593Smuzhiyun 345*4882a593SmuzhiyunB<parse_headers.pl> [<options>] <C_FILE> <OUT_FILE> [<EXCEPTIONS_FILE>] 346*4882a593Smuzhiyun 347*4882a593SmuzhiyunWhere <options> can be: --debug, --help or --usage. 348*4882a593Smuzhiyun 349*4882a593Smuzhiyun=head1 OPTIONS 350*4882a593Smuzhiyun 351*4882a593Smuzhiyun=over 8 352*4882a593Smuzhiyun 353*4882a593Smuzhiyun=item B<--debug> 354*4882a593Smuzhiyun 355*4882a593SmuzhiyunPut the script in verbose mode, useful for debugging. 356*4882a593Smuzhiyun 357*4882a593Smuzhiyun=item B<--usage> 358*4882a593Smuzhiyun 359*4882a593SmuzhiyunPrints a brief help message and exits. 360*4882a593Smuzhiyun 361*4882a593Smuzhiyun=item B<--help> 362*4882a593Smuzhiyun 363*4882a593SmuzhiyunPrints a more detailed help message and exits. 364*4882a593Smuzhiyun 365*4882a593Smuzhiyun=back 366*4882a593Smuzhiyun 367*4882a593Smuzhiyun=head1 DESCRIPTION 368*4882a593Smuzhiyun 369*4882a593SmuzhiyunConvert a C header or source file (C_FILE), into a ReStructured Text 370*4882a593Smuzhiyunincluded via ..parsed-literal block with cross-references for the 371*4882a593Smuzhiyundocumentation files that describe the API. It accepts an optional 372*4882a593SmuzhiyunEXCEPTIONS_FILE with describes what elements will be either ignored or 373*4882a593Smuzhiyunbe pointed to a non-default reference. 374*4882a593Smuzhiyun 375*4882a593SmuzhiyunThe output is written at the (OUT_FILE). 376*4882a593Smuzhiyun 377*4882a593SmuzhiyunIt is capable of identifying defines, functions, structs, typedefs, 378*4882a593Smuzhiyunenums and enum symbols and create cross-references for all of them. 379*4882a593SmuzhiyunIt is also capable of distinguish #define used for specifying a Linux 380*4882a593Smuzhiyunioctl. 381*4882a593Smuzhiyun 382*4882a593SmuzhiyunThe EXCEPTIONS_FILE contain two rules to allow ignoring a symbol or 383*4882a593Smuzhiyunto replace the default references by a custom one. 384*4882a593Smuzhiyun 385*4882a593SmuzhiyunPlease read Documentation/doc-guide/parse-headers.rst at the Kernel's 386*4882a593Smuzhiyuntree for more details. 387*4882a593Smuzhiyun 388*4882a593Smuzhiyun=head1 BUGS 389*4882a593Smuzhiyun 390*4882a593SmuzhiyunReport bugs to Mauro Carvalho Chehab <mchehab@kernel.org> 391*4882a593Smuzhiyun 392*4882a593Smuzhiyun=head1 COPYRIGHT 393*4882a593Smuzhiyun 394*4882a593SmuzhiyunCopyright (c) 2016 by Mauro Carvalho Chehab <mchehab+samsung@kernel.org>. 395*4882a593Smuzhiyun 396*4882a593SmuzhiyunLicense GPLv2: GNU GPL version 2 <https://gnu.org/licenses/gpl.html>. 397*4882a593Smuzhiyun 398*4882a593SmuzhiyunThis is free software: you are free to change and redistribute it. 399*4882a593SmuzhiyunThere is NO WARRANTY, to the extent permitted by law. 400*4882a593Smuzhiyun 401*4882a593Smuzhiyun=cut 402