1 #! /usr/bin/perl -w 2 3 # get-pci-ids: extract pci vendor/device ids from linux net drivers 4 5 # Copyright (C) 2003 Georg Baum <gbaum (at] users.sf.net> 6 7 # This program is free software; you can redistribute it and/or modify 8 # it under the terms of the GNU General Public License as published by 9 # the Free Software Foundation; either version 2 of the License, or 10 # (at your option) any later version. 11 12 # This program is distributed in the hope that it will be useful, 13 # but WITHOUT ANY WARRANTY; without even the implied warranty of 14 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 # GNU General Public License for more details. 16 17 # You should have received a copy of the GNU General Public License 18 # along with this program; if not, write to the Free Software 19 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 20 21 22 # Known bugs/limitations: 23 # - Does not recognize all drivers because some require special cflags. 24 # Fails also on some drivers that do belong to other architectures 25 # than the one of the machine this script is running on. 26 # This is currently not so important because all drivers that have an 27 # Etherboot counterpart are recognized. 28 29 30 use strict; 31 use File::Basename "dirname"; 32 use POSIX "uname"; 33 34 # Where to find the kernel sources 35 my $kernel_src = "/usr/src/linux"; 36 37 if($#ARGV >= 0) { 38 $kernel_src = shift; 39 } 40 41 # Sanity checks 42 if($#ARGV >= 0) { 43 print STDERR "Too many arguments.\n"; 44 print STDERR "Usage: get-pci-ids [path to kernel sources]\n"; 45 print STDERR " /usr/src/linux is assumed if no path is given.\n"; 46 exit 1; 47 } 48 49 unless(-f "$kernel_src/include/linux/version.h") { 50 print STDERR "Could not find $kernel_src/include/linux/version.h.\n"; 51 print STDERR "$kernel_src is probably no Linux kernel source tree.\n"; 52 exit 1; 53 } 54 55 # Flags that are needed to preprocess the drivers. 56 # Some drivers need optimization 57 my $cflags="-D__KERNEL__ -I$kernel_src/include -I$kernel_src/net/inet -O2"; 58 59 # The C preprocessor. It needs to spit out the preprocessed source on stdout. 60 my $cpp="gcc -E"; 61 62 # List of drivers. We parse every .c file. It does not harm if it does not contain a driver. 63 my @drivers = split /\s+/, `find $kernel_src/drivers/net -name '*.c' | sort`; 64 65 # Kernel version 66 my $version = `grep UTS_RELEASE $kernel_src/include/linux/version.h`; 67 chomp $version; 68 $version =~ s/\s*#define\s+UTS_RELEASE\s+"(\S+)".*$/$1/g; 69 70 # Architecture 71 my @uname = uname(); 72 73 74 # Print header 75 print "# PCI vendor/device ids extracted from Linux $version on $uname[4] at " . gmtime() . "\n"; 76 77 my $driver; 78 79 # Process the drivers 80 foreach $driver (@drivers) { 81 82 # Preprocess to expand macros 83 my $command = "$cpp $cflags -I" . dirname($driver) . " $driver"; 84 open DRIVER, "$command |" or die "Could not execute\n\"$command\".\n"; 85 86 # Extract the pci_device_id structure 87 my $found = 0; 88 my $line = ""; 89 my @lines; 90 while(<DRIVER>) { 91 if(/^\s*static\s+struct\s+pci_device_id/) { 92 # This file contains a driver. Print the name. 93 $driver =~ s!$kernel_src/drivers/net/!!g; 94 print "\n$driver\n"; 95 $found = 1; 96 next; 97 } 98 if($found == 1){ 99 if(/\};/ or /{\s*0\s*,?\s*}/) { 100 # End of struct 101 $found = 0; 102 } else { 103 chomp; 104 if(/\}\s*,?\s*\n?$/) { 105 # This line contains a full entry or the last part of it. 106 $_ = $line . $_; 107 $line = ""; 108 s/[,\{\};\(\)]//g; # Strip punctuation 109 s/^\s+//g; # Eat whitespace at beginning of line 110 tr[A-Z][a-z]; # Convert to lowercase 111 # Push the vendor and device id to @lines if this line is not empty. 112 # We ignore everything else that might be there 113 my ($vendor_id, $device_id, $remainder) = split /\W+/, $_, 3; 114 push @lines, "$vendor_id $device_id\n" if($vendor_id && $device_id); 115 } else { 116 # This line does contain a partial entry. Remember it. 117 $line .= "$_ "; 118 } 119 } 120 } 121 } 122 close DRIVER; # No "or die", because $cpp fails on some files 123 124 # Now print out the sorted values 125 @lines = sort @lines; 126 my $lastline = ""; 127 foreach(@lines) { 128 # Print each vendor/device id combination only once. 129 # Some drivers (e.g. e100) do contain subfamilies 130 print if($_ ne $lastline); 131 $lastline = $_; 132 } 133 } 134 135 136