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@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 30use strict; 31use File::Basename "dirname"; 32use POSIX "uname"; 33 34# Where to find the kernel sources 35my $kernel_src = "/usr/src/linux"; 36 37if($#ARGV >= 0) { 38 $kernel_src = shift; 39} 40 41# Sanity checks 42if($#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 49unless(-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 57my $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. 60my $cpp="gcc -E"; 61 62# List of drivers. We parse every .c file. It does not harm if it does not contain a driver. 63my @drivers = split /\s+/, `find $kernel_src/drivers/net -name '*.c' | sort`; 64 65# Kernel version 66my $version = `grep UTS_RELEASE $kernel_src/include/linux/version.h`; 67chomp $version; 68$version =~ s/\s*#define\s+UTS_RELEASE\s+"(\S+)".*$/$1/g; 69 70# Architecture 71my @uname = uname(); 72 73 74# Print header 75print "# PCI vendor/device ids extracted from Linux $version on $uname[4] at " . gmtime() . "\n"; 76 77my $driver; 78 79# Process the drivers 80foreach $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