You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

parserom.pl 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. #!/usr/bin/env perl
  2. #
  3. # Parse PCI_ROM and ISA_ROM entries from source file(s) specified as
  4. # arguments and output the relevant Makefile rules to STDOUT.
  5. #
  6. # Originally based on portions of Ken Yap's genrules.pl. Completely
  7. # rewritten by Robin Smidsrød to be more maintainable.
  8. use strict;
  9. use warnings;
  10. use Getopt::Long;
  11. # Parse command-line options
  12. my @exclude_driver_classes = ();
  13. my @exclude_drivers = ();
  14. my $debug = 0;
  15. my $help = 0;
  16. GetOptions(
  17. "exclude-driver-class=s" => \@exclude_driver_classes,
  18. "exclude-driver=s" => \@exclude_drivers,
  19. "debug" => \$debug,
  20. "help" => \$help,
  21. );
  22. # Convert exclution arrays to lookup tables
  23. my $exclude_driver_class_map = { map { $_ => 1 } @exclude_driver_classes };
  24. my $exclude_driver_map = { map { $_ => 1 } @exclude_drivers };
  25. # Ensure STDOUT and STDERR are synchronized if debugging
  26. if ( $debug ) {
  27. STDOUT->autoflush(1);
  28. STDERR->autoflush(1);
  29. }
  30. # Compile regular expressions here for slight performance boost
  31. my %RE = (
  32. 'parse_driver_class' => qr{ drivers/ (\w+?) / }x,
  33. 'parse_family' => qr{^ (?:\./)? (.*) \..+? $}x,
  34. 'find_rom_line' => qr/^ \s* ( (PCI|ISA)_ROM \s* \( \s* (.*?) ) $/x,
  35. 'extract_pci_id' => qr/^ \s* 0x([0-9A-Fa-f]{4}) \s* ,? \s* (.*) $/x,
  36. 'extract_quoted_string' => qr/^ \s* \" ([^\"]*?) \" \s* ,? \s* (.*) $/x,
  37. );
  38. # Show help if required arguments are missing or help was requested
  39. show_usage_and_exit() if $help or @ARGV < 1;
  40. # Process each source file specified
  41. process_source_file($_) for @ARGV;
  42. exit;
  43. sub show_usage_and_exit {
  44. print STDERR <<"EOM";
  45. Syntax: $0 [<options>] <source-file> [<source-file>]
  46. Options:
  47. --exclude-driver-class Exclude specified driver classes
  48. --exclude-driver Exclude specified drivers
  49. --debug Output debug information on STDERR
  50. --help This help information
  51. EOM
  52. exit 1;
  53. }
  54. # Figure out if source file is a driver and look for ROM declarations
  55. sub process_source_file {
  56. my ($source_file) = @_;
  57. return unless defined $source_file;
  58. return unless length $source_file;
  59. my $state = { 'source_file' => $source_file };
  60. log_debug("SOURCE_FILE", $state->{source_file});
  61. # Skip source files that aren't drivers
  62. parse_driver_class( $state );
  63. unless ( $state->{'driver_class'} ) {
  64. log_debug("SKIP_NOT_DRIVER", $state->{source_file} );
  65. return;
  66. }
  67. # Skip source files with driver classes that are explicitly excluded
  68. if ( $exclude_driver_class_map->{ $state->{'driver_class'} } ) {
  69. log_debug("SKIP_EXCL_CLASS", $state->{'driver_class'} );
  70. return;
  71. }
  72. # Skip source files without driver information
  73. parse_family( $state );
  74. parse_driver_name( $state );
  75. unless ( $state->{'family'} and $state->{'driver_name'} ) {
  76. log_debug("SKIP_NO_DRV_INFO", $state->{source_file} );
  77. return;
  78. }
  79. # Skip source files with drivers that are explicitly excluded
  80. if ( $exclude_driver_map->{ $state->{'driver_name'} } ) {
  81. log_debug("SKIP_EXCL_DRV", $state->{'driver_name'} );
  82. return;
  83. }
  84. # Iterate through lines in source files looking for ROM declarations
  85. # and # output Makefile rules
  86. open( my $fh, "<", $state->{'source_file'} )
  87. or die "Couldn't open $state->{source_file}: $!\n";
  88. while (<$fh>) {
  89. process_rom_decl($state, $1, $2, $3) if m/$RE{find_rom_line}/;
  90. }
  91. close($fh) or die "Couldn't close $source_file: $!\n";
  92. return 1;
  93. }
  94. # Verify that the found ROM declaration is sane and dispatch to the right
  95. # handler depending on type
  96. sub process_rom_decl {
  97. my ($state, $rom_line, $rom_type, $rom_decl) = @_;
  98. return unless defined $rom_line;
  99. return unless length $rom_line;
  100. log_debug("ROM_LINE", $rom_line);
  101. return unless defined $rom_type;
  102. return unless length $rom_type;
  103. log_debug("ROM_TYPE", $rom_type);
  104. $state->{'type'} = lc $rom_type;
  105. return process_pci_rom($state, $rom_decl) if $rom_type eq "PCI";
  106. return process_isa_rom($state, $rom_decl) if $rom_type eq "ISA";
  107. return;
  108. }
  109. # Extract values from PCI_ROM declaration lines and dispatch to
  110. # Makefile rule generator
  111. sub process_pci_rom {
  112. my ($state, $decl) = @_;
  113. return unless defined $decl;
  114. return unless length $decl;
  115. (my $vendor, $decl) = extract_pci_id($decl, 'PCI_VENDOR');
  116. (my $device, $decl) = extract_pci_id($decl, 'PCI_DEVICE');
  117. (my $image, $decl) = extract_quoted_string($decl, 'IMAGE');
  118. (my $desc, $decl) = extract_quoted_string($decl, 'DESCRIPTION');
  119. if ( $vendor and $device and $image and $desc ) {
  120. print_make_rules( $state, "${vendor}${device}", $desc, $vendor, $device );
  121. print_make_rules( $state, $image, $desc, $vendor, $device, 1 );
  122. }
  123. else {
  124. log_debug("WARNING", "Malformed PCI_ROM macro on line $. of $state->{source_file}");
  125. }
  126. return 1;
  127. }
  128. # Extract values from ISA_ROM declaration lines and dispatch to
  129. # Makefile rule generator
  130. sub process_isa_rom {
  131. my ($state, $decl) = @_;
  132. return unless defined $decl;
  133. return unless length $decl;
  134. (my $image, $decl) = extract_quoted_string($decl, 'IMAGE');
  135. (my $desc, $decl) = extract_quoted_string($decl, 'DESCRIPTION');
  136. if ( $image and $desc ) {
  137. print_make_rules( $state, $image, $desc );
  138. }
  139. else {
  140. log_debug("WARNING", "Malformed ISA_ROM macro on line $. of $state->{source_file}");
  141. }
  142. return 1;
  143. }
  144. # Output Makefile rules for the specified ROM declarations
  145. sub print_make_rules {
  146. my ( $state, $image, $desc, $vendor, $device, $dup ) = @_;
  147. unless ( $state->{'is_header_printed'} ) {
  148. print "# NIC\t\n";
  149. print "# NIC\tfamily\t$state->{family}\n";
  150. print "DRIVERS_$state->{driver_class} += $state->{driver_name}\n";
  151. print "DRIVERS += $state->{driver_name}\n";
  152. print "\n";
  153. $state->{'is_header_printed'} = 1;
  154. }
  155. return if $vendor and ( $vendor eq "ffff" or $device eq "ffff" );
  156. my $ids = $vendor ? "$vendor,$device" : "-";
  157. print "# NIC\t$image\t$ids\t$desc\n";
  158. print "DRIVER_$image = $state->{driver_name}\n";
  159. print "ROM_TYPE_$image = $state->{type}\n";
  160. print "ROM_DESCRIPTION_$image = \"$desc\"\n";
  161. print "PCI_VENDOR_$image = 0x$vendor\n" if $vendor;
  162. print "PCI_DEVICE_$image = 0x$device\n" if $device;
  163. print "ROMS += $image\n" unless $dup;
  164. print "ROMS_$state->{driver_name} += $image\n" unless $dup;
  165. print "\n";
  166. return 1;
  167. }
  168. # Driver class is whatever comes after the "drivers" part of the filename (relative path)
  169. sub parse_driver_class {
  170. my ($state) = @_;
  171. my $filename = $state->{'source_file'};
  172. return unless defined $filename;
  173. return unless length $filename;
  174. if ( $filename =~ m/$RE{parse_driver_class}/ ) {
  175. log_debug("DRIVER_CLASS", $1);
  176. $state->{'driver_class'} = $1;
  177. }
  178. return;
  179. }
  180. # Family name is filename (relative path) without extension
  181. sub parse_family {
  182. my ($state) = @_;
  183. my $filename = $state->{'source_file'};
  184. return unless defined $filename;
  185. return unless length $filename;
  186. if ( $filename =~ m/$RE{parse_family}/ ) {
  187. log_debug("FAMILY", $1);
  188. $state->{'family'} = $1;
  189. }
  190. return;
  191. }
  192. # Driver name is last part of family name
  193. sub parse_driver_name {
  194. my ($state) = @_;
  195. my $family = $state->{'family'};
  196. return unless defined $family;
  197. return unless length $family;
  198. my @parts = split "/", $family;
  199. $state->{'driver_name'} = $parts[-1];
  200. log_debug("DRIVER", $state->{'driver_name'});
  201. return;
  202. }
  203. # Extract a PCI vendor/device ID e.g. 0x8086, possibly followed by a comma
  204. # Should always be 4-digit lower-case hex number
  205. sub extract_pci_id {
  206. my ($str, $label) = @_;
  207. return "", $str unless defined $str;
  208. return "", $str unless length $str;
  209. if ( $str =~ m/$RE{extract_pci_id}/ ) {
  210. my $id = lc $1;
  211. log_debug($label, $id);
  212. return $id, $2;
  213. }
  214. return "", $str;
  215. }
  216. # Extract a double-quoted string, possibly followed by a comma
  217. sub extract_quoted_string {
  218. my ($str, $label) = @_;
  219. return "", $str unless defined $str;
  220. return "", $str unless length $str;
  221. if ( $str =~ m/$RE{extract_quoted_string}/ ) {
  222. log_debug($label, $1);
  223. return $1, $2;
  224. }
  225. return "", $str;
  226. }
  227. # Output debug info to STDERR (off by default)
  228. sub log_debug {
  229. my ($label, $str) = @_;
  230. return unless $debug;
  231. return unless defined $str;
  232. print STDERR "\n" if $label eq 'SOURCE_FILE';
  233. print STDERR "=";
  234. if ( defined $label ) {
  235. my $pad_count = 16 - length $label;
  236. print STDERR $label . ":" . ( " " x $pad_count );
  237. }
  238. print STDERR $str . "\n";
  239. return;
  240. }