1254852Sdumbbell#!/usr/bin/perl
2254852Sdumbbell# $FreeBSD$
3254852Sdumbbell
4254852Sdumbbelluse strict;
5254852Sdumbbelluse warnings;
6254852Sdumbbelluse utf8;
7254852Sdumbbell
8254852Sdumbbelluse File::Basename;
9254852Sdumbbell
10254852Sdumbbellmy $progname = basename($0);
11254852Sdumbbell
12254852Sdumbbellsub parse_linux_header ($)
13254852Sdumbbell{
14254852Sdumbbell    my ($header) = @_;
15254852Sdumbbell
16254852Sdumbbell    open(my $fh, '<', $header) or die "Can't open Linux header: $!\n";
17254852Sdumbbell
18254852Sdumbbell    my $in_list = 0;
19254852Sdumbbell
20254852Sdumbbell    my %pciids = ();
21254852Sdumbbell
22254852Sdumbbell    my $current_vendor_define;
23254852Sdumbbell
24254852Sdumbbell    while (my $line = <$fh>) {
25254852Sdumbbell        if ($line =~ /^#define +([^ ]+) +/) {
26254852Sdumbbell            $current_vendor_define = $1;
27254852Sdumbbell            $pciids{$current_vendor_define} = {};
28254852Sdumbbell        } elsif ($line =~ /^\t\{0x([0-9a-fA-F]{4}), *0x([0-9a-fA-F]{4}),[^,]+,[^,]+,[^,]+,[^,]+, *([^}]+)\}/) {
29254852Sdumbbell            my $vendor_id = uc($1);
30254852Sdumbbell            my $device_id = uc($2);
31254852Sdumbbell            my $flags     = $3;
32254852Sdumbbell
33254852Sdumbbell            $pciids{$current_vendor_define}{$device_id} = {
34254852Sdumbbell                'vendor_id' => $vendor_id,
35254852Sdumbbell                'flags'     => $flags
36254852Sdumbbell            };
37254852Sdumbbell        }
38254852Sdumbbell    }
39254852Sdumbbell
40254852Sdumbbell    close($fh);
41254852Sdumbbell
42254852Sdumbbell    return %pciids;
43254852Sdumbbell}
44254852Sdumbbell
45254852Sdumbbellsub parse_freebsd_header ($) {
46254852Sdumbbell    my ($header) = @_;
47254852Sdumbbell
48254852Sdumbbell    open(my $fh, '<', $header) or die "Can't open FreeBSD header: $!\n";
49254852Sdumbbell
50254852Sdumbbell    my $in_list = 0;
51254852Sdumbbell
52254852Sdumbbell    my %pciids = ();
53254852Sdumbbell
54254852Sdumbbell    my $current_vendor_define;
55254852Sdumbbell
56254852Sdumbbell    while (my $line = <$fh>) {
57254852Sdumbbell        if ($line =~ /^#define +([^ ]+) +/) {
58254852Sdumbbell            $current_vendor_define = $1;
59254852Sdumbbell            $pciids{$current_vendor_define} = {};
60254852Sdumbbell        } elsif ($line =~ /^\t\{0x([0-9a-fA-F]{4}), *0x([0-9a-fA-F]{4}), *([^,]+), *"([^"]+)"\}/) {
61254852Sdumbbell            my $vendor_id = uc($1);
62254852Sdumbbell            my $device_id = uc($2);
63254852Sdumbbell            my $flags     = $3;
64254852Sdumbbell            my $name      = $4;
65254852Sdumbbell
66254852Sdumbbell            $pciids{$current_vendor_define}{$device_id} = {
67254852Sdumbbell                'vendor_id' => $vendor_id,
68254852Sdumbbell                'flags'     => $flags,
69254852Sdumbbell                'name'      => $name
70254852Sdumbbell            };
71254852Sdumbbell        }
72254852Sdumbbell    }
73254852Sdumbbell
74254852Sdumbbell    close($fh);
75254852Sdumbbell
76254852Sdumbbell    return %pciids;
77254852Sdumbbell}
78254852Sdumbbell
79254852Sdumbbellsub parse_pciids_db ($) {
80254852Sdumbbell    my ($header) = @_;
81254852Sdumbbell
82254852Sdumbbell    open(my $fh, '<', $header) or die "Can't open PCI IDs database: $!\n";
83254852Sdumbbell
84254852Sdumbbell    my %pciids = ();
85254852Sdumbbell
86254852Sdumbbell    my $current_vendor_id;
87254852Sdumbbell
88254852Sdumbbell    while (my $line = <$fh>) {
89254852Sdumbbell        if (!$line || $line =~ /^#/) {
90254852Sdumbbell            next;
91254852Sdumbbell        }
92254852Sdumbbell        if ($line =~ /^([0-9a-fA-F]{4})  (.+)/) {
93254852Sdumbbell            # Vendor ID & name.
94254852Sdumbbell            my $vendor_id   = uc($1);
95254852Sdumbbell            my $vendor_name = $2;
96254852Sdumbbell            $pciids{$vendor_id} = {
97254852Sdumbbell                'name'    => $vendor_name,
98254852Sdumbbell                'devices' => {}
99254852Sdumbbell            };
100254852Sdumbbell
101254852Sdumbbell            $current_vendor_id = $vendor_id;
102254852Sdumbbell        } elsif ($line =~ /^\t([0-9a-fA-F]{4})  (.+)/) {
103254852Sdumbbell            # Device ID & name.
104254852Sdumbbell            my $device_id   = uc($1);
105254852Sdumbbell            my $device_name = $2;
106254852Sdumbbell            $pciids{$current_vendor_id}{'devices'}{$device_id} = $device_name;
107254852Sdumbbell        }
108254852Sdumbbell    }
109254852Sdumbbell
110254852Sdumbbell    close($fh);
111254852Sdumbbell
112254852Sdumbbell    return %pciids;
113254852Sdumbbell}
114254852Sdumbbell
115254852Sdumbbellif (scalar(@ARGV) != 3) {
116254852Sdumbbell    print STDERR "Syntax: $progname <linux_header> <freebsd_header> <pciids_db> [<vendor_define>]\n";
117254852Sdumbbell    exit 1;
118254852Sdumbbell}
119254852Sdumbbell
120254852Sdumbbellmy $linux_header   = $ARGV[0];
121254852Sdumbbellmy $freebsd_header = $ARGV[1];
122254852Sdumbbellmy $pciids_db      = $ARGV[2];
123254852Sdumbbellmy $only_vendor    = $ARGV[3];
124254852Sdumbbell
125254852Sdumbbellmy %linux_pciids   = parse_linux_header($linux_header);
126254852Sdumbbellmy %freebsd_pciids = parse_freebsd_header($freebsd_header);
127254852Sdumbbellmy %pciids_db      = parse_pciids_db($pciids_db);
128254852Sdumbbell
129254852Sdumbbellprint STDERR "Update FreeBSD's PCI IDs:\n";
130254852Sdumbbellforeach my $vendor_define (sort keys(%linux_pciids)) {
131254852Sdumbbell    if ($only_vendor && $vendor_define ne $only_vendor) {
132254852Sdumbbell        print STDERR "(skip unwanted define: $vendor_define)\n";
133254852Sdumbbell        next;
134254852Sdumbbell    } elsif (!$only_vendor && !exists($freebsd_pciids{$vendor_define})) {
135254852Sdumbbell        print STDERR "(skip unsupport define: $vendor_define)\n";
136254852Sdumbbell        next;
137254852Sdumbbell    }
138254852Sdumbbell
139254852Sdumbbell    foreach my $device_id (sort keys(%{$linux_pciids{$vendor_define}})) {
140254852Sdumbbell        my $vendor_id = $linux_pciids{$vendor_define}{$device_id}{'vendor_id'};
141254852Sdumbbell
142254852Sdumbbell        if (exists($freebsd_pciids{$vendor_define}{$device_id})) {
143254852Sdumbbell            print STDERR "  $vendor_define: $vendor_id:$device_id already in header\n";
144254852Sdumbbell            next;
145254852Sdumbbell        }
146254852Sdumbbell
147254852Sdumbbell        my $flags     = $linux_pciids{$vendor_define}{$device_id}{'flags'};
148254852Sdumbbell        my $name      = $pciids_db{$vendor_id}{'devices'}{$device_id} || "Unknown device name";
149254852Sdumbbell        print STDERR "  $vendor_define: $vendor_id:$device_id is missing ($name)\n";
150254852Sdumbbell        $freebsd_pciids{$vendor_define}{$device_id} = {
151254852Sdumbbell            'vendor_id' => $vendor_id,
152254852Sdumbbell            'flags'     => $flags,
153254852Sdumbbell            'name'      => $name
154254852Sdumbbell        };
155254852Sdumbbell    }
156254852Sdumbbell}
157254852Sdumbbell
158254852Sdumbbellprint STDERR "\nWrite FreeBSD header to stdout...\n";
159254852Sdumbbellprint <<"EOF";
160254852Sdumbbell/*
161254852Sdumbbell * \$FreeBSD\$
162254852Sdumbbell */
163254852Sdumbbell
164254852Sdumbbell/*
165254852Sdumbbell * Generated by $progname from:
166254852Sdumbbell *   o  previous FreeBSD's drm_pciids.h
167254852Sdumbbell *   o  Linux' drm_pciids.h
168254852Sdumbbell *   o  the PCI ID repository (http://pciids.sourceforge.net/)
169254852Sdumbbell *
170254852Sdumbbell * See tools/tools/drm/$progname.
171254852Sdumbbell */
172254852SdumbbellEOF
173254852Sdumbbellforeach my $vendor_define (sort keys(%freebsd_pciids)) {
174254852Sdumbbell    print "\n#define $vendor_define \\\n";
175254852Sdumbbell    foreach my $device_id (sort keys(%{$freebsd_pciids{$vendor_define}})) {
176254852Sdumbbell        my $vendor_id = $freebsd_pciids{$vendor_define}{$device_id}{'vendor_id'};
177254852Sdumbbell        my $flags     = $freebsd_pciids{$vendor_define}{$device_id}{'flags'};
178254852Sdumbbell        my $name      = $freebsd_pciids{$vendor_define}{$device_id}{'name'};
179254852Sdumbbell
180254852Sdumbbell        print "\t{0x$vendor_id, 0x$device_id, $flags, \"$name\"}, \\\n";
181254852Sdumbbell    }
182254852Sdumbbell    print "\t{0, 0, 0, NULL}\n";
183254852Sdumbbell}
184