/[soft]/ldetect-lst/trunk/convert/merge2pcitable.pl
ViewVC logotype

Contents of /ldetect-lst/trunk/convert/merge2pcitable.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1357 - (show annotations) (download)
Tue May 17 09:21:22 2011 UTC (10 years, 1 month ago) by dmorgan
File MIME type: text/plain
File size: 18531 byte(s)
Import  ldetect
1 #!/usr/bin/perl
2
3 use MDK::Common;
4
5
6 my @ignored_modules = (
7 qw(alsa ignore),
8 );
9
10 my ($force, @force_modules, $all, $keep_subids, $wildcards, $use_description);
11
12 # UPDATE ME WHEN UPDATING ../lst/Cards+:
13 my $ati_driver = 'Card:ATI Radeon HD 2000 and later (radeon/fglrx)';
14 my $ati_driver_rhd = 'Card:ATI Radeon HD 2000 and later (radeonhd/fglrx)';
15 my $ati_driver_vesa= 'Card:ATI Radeon HD 2000 and later (vesa/fglrx)';
16 my $ati_free_only = 'Card:ATI Radeon X1950 and earlier';
17 my $ati_rhd_only = 'Card:ATI Radeon RV710 9592';
18 # also, be careful when merging as Cards+ and pcitable may contain card-specific
19 # cases due to bugs in the various drivers
20
21 if ($0 =~ /merge2pcitable/)
22 {
23 if ($ARGV[0] =~ /^-f=?(.*)$/) {
24 shift;
25 @force_modules = split(/,/, $1);
26 $force = !@force_modules;
27 }
28 $ARGV[0] eq '-a' and $all = shift;
29 $ARGV[0] eq '--keep-subids' and $keep_subids = shift;
30 $ARGV[0] eq '--handle-wildcards' and $wildcards = shift;
31 $ARGV[0] eq '--old' and $use_description = shift;
32
33 my $formats = join '|', grep { $_ } map { /^read_(.*)/ ? $1 : '' } keys %main::;
34
35 @ARGV == 3 or die "usage: $0 [-f[=module1,...]] [-a] [--old] $formats <in_file> <mdk_pcitable>\n";
36
37 my ($format, $in, $pcitable) = @ARGV;
38
39 my $read = $main::{"read_$format"} or die "unknown format $format (must be one of $formats)\n";
40 my $d_pci = read_pcitable($pcitable, 'strict');
41 my ($d_in, $classes) = $read->($in);
42
43 if ($format eq 'kernel_aliasmap' || $format eq 'fglrxko_pci_ids_h') {
44 foreach (keys %$d_pci) {
45 if (member($d_pci->{$_}[0], ($ati_driver, $ati_driver_rhd, $ati_driver_vesa)) && !$d_in->{$_}[0]) {
46 # support dropped, handle:
47 if ($d_pci->{$_}[0] eq $ati_driver) {
48 $d_pci->{$_}[0] = $ati_free_only;
49 } elsif ($d_pci->{$_}[0] eq $ati_driver_vesa) {
50 delete $d_pci->{$_};
51 } elsif ($d_pci->{$_}[0] eq $ati_driver_rhd) {
52 $d_pci->{$_}[0] = $ati_rhd_only
53 } else {
54 die 'not handled ' . $_;
55 }
56 } elsif (member($d_pci->{$_}[0], ($ati_free_only, $ati_rhd_only)) && $d_in->{$_}[0]) {
57 # support added for pre-existing entry, handle:
58 if ($d_pci->{$_}[0] eq $ati_free_only) {
59 $d_pci->{$_}[0] = $ati_driver;
60 } elsif ($d_pci->{$_}[0] eq $ati_rhd_only) {
61 $d_pci->{$_}[0] = $ati_driver_rhd;
62 } else {
63 die 'not handled ' . $_;
64 }
65 }
66 }
67 }
68 # Here we hack around so that drivers get used in order radeon, radeonhd, vesa:
69 if ($format eq 'ati_pciids_csv') {
70 foreach (keys %$d_pci) {
71 if (member($d_pci->{$_}[0], ($ati_driver, $ati_free_only)) && !$d_in->{$_}[0]) {
72 # support dropped, handle:
73 if ($d_pci->{$_}[0] eq $ati_driver) {
74 $d_pci->{$_}[0] = $ati_driver_vesa;
75 } elsif ($d_pci->{$_}[0] eq $ati_free_only) {
76 delete $d_pci->{$_};
77 } else {
78 die 'not handled ' . $_;
79 }
80 } elsif (member($d_pci->{$_}[0], ($ati_driver_rhd, $ati_driver_vesa, $ati_rhd_only)) && $d_in->{$_}[0]) {
81 # support added for pre-existing entry, handle:
82 next if $_ eq "10029610ffffffff"; # see Cards+ and #49824
83 if (member($d_pci->{$_}[0], ($ati_driver_rhd, $ati_driver_vesa))) {
84 $d_pci->{$_}[0] = $ati_driver;
85 } elsif ($d_pci->{$_}[0] eq $ati_rhd_only) {
86 $d_pci->{$_}[0] = $ati_free_only;
87 } else {
88 die 'not handled ' . $_;
89 }
90 }
91 }
92 }
93 if ($format eq 'rhd_id_c') {
94 foreach (keys %$d_pci) {
95 if (member($d_pci->{$_}[0], ($ati_driver_rhd, $ati_rhd_only)) && !$d_in->{$_}[0]) {
96 # support dropped, handle:
97 if ($d_pci->{$_}[0] eq $ati_driver_rhd) {
98 $d_pci->{$_}[0] = $ati_driver_vesa;
99 } elsif ($d_pci->{$_}[0] eq $ati_rhd_only) {
100 delete $d_pci->{$_};
101 } else {
102 die 'not handled ' . $_;
103 }
104 } elsif ($d_pci->{$_}[0] eq $ati_driver_vesa && $d_in->{$_}[0]) {
105 # support added for pre-existing entry, handle:
106 $d_pci->{$_}[0] = $ati_driver_rhd;
107 }
108 }
109 }
110
111 merge($d_pci, $d_in, $classes);
112 exit 1 if our $error;
113 cleanup_subids($d_pci) if !$keep_subids;
114 write_pcitable($d_pci);
115 } else { 1 }
116
117 sub dummy_module {
118 my ($m) = @_;
119 $m =~ s/"(.*)"/$1/;
120 member($m, @ignored_modules);
121 }
122
123 sub to_string {
124 my ($id, $driver) = @_;
125 @$driver >= 1 or error("error: to_string $id");
126 my ($module, $text) = map { defined($_) && qq("$_") } @$driver;
127 my ($id1, $id2, $subid1, $subid2) = map { "0x$_" } ($id =~ /(....)/g);
128 join "\t", $id1, $id2, if_("$subid1 $subid2" ne "0xffff 0xffff", $subid1, $subid2), $module, if_($use_description && $text, $text);
129 }
130
131 sub read_rhpcitable {
132 my ($f, $strict) = @_;
133 read_pcitable($f, $strict, 1);
134 }
135
136 # works for RedHat's pcitable old and new format, + mdk format (alike RedHat's old one)
137 # (the new format has ending .o's and double quotes are removed)
138 sub read_pcitable {
139 my ($f, $strict, $newer_rh_format) = @_;
140 my %drivers;
141 my %class;
142 my $line = 0;
143 my $rm_quote_silent = sub { local ($_) = @_; s/^"//; s/"$//; $_ };
144 my $rm_quote = sub {
145 local ($_) = @_;
146 s/^"// or error("$f:$line: missing left quote");
147 s/"$// or error("$f:$line: missing right quote");
148 /"/ && $strict and error("$f:$line: bad double quote");
149 $_;
150 };
151 foreach (eval { catMaybeCompressed($f) }) {
152 chomp; $line++;
153 next if /^#/ || /^\s*$/;
154
155 if (!$strict) {
156 #- help poor written pcitable's like redhat's :)
157 s/(\S+)\s+(\S+)\s+(.*)/$1\t$2\t$3/;
158 }
159
160 if (my ($id1, $id2, @l) = split /\t+/) {
161 push @l, '""' if $newer_rh_format;
162 my ($subid1, $subid2) = ('ffff', 'ffff');
163 ($subid1, $subid2, @l) = @l if @l > 2;
164 @l == 1 || @l == 2 or die "$f:$line: bad number of fields " . (int @l) . " (in $_)\n";
165 my ($module, $text) = @l;
166
167 my $class = $text =~ /(.*?)|/;
168 my $id1_ = $rm_quote_silent->($id1);
169 if (defined $text && $class{$id1_}) {
170 print STDERR "$f:$line: class $id1_ named both $class and $class{$id1_}, taking $class{$id1_}\n";
171 $class{$id1_} ||= $1;
172 $text =~ s/(.*?)|/$class{$id1_}|/;
173 }
174
175 $module =~ s/\.o$//;
176 $module = '"unknown"' if dummy_module($module);
177 $module = '"unknown"' if $id1 eq '0x1011' && $id2 eq '0x0004';
178 # known errors in redhat's pcitable
179 # these are pci to pci bridge
180 $module = '"yenta_socket"' if $module =~ /i82365/;
181 my $id = join '', map {
182 s/^0x//;
183 length == 4 or error("$f:$line: bad number $_");
184 lc($_);
185 } $id1, $id2, $subid1, $subid2;
186 $drivers{$id} && $strict and error("$f:$line: multiple entry for $id (skipping $module $text)");
187 $drivers{$id} ||= [ $rm_quote->($module), defined($text) ? $rm_quote->($text) : undef, $line ];
188 } else {
189 die "$f:$line: bad line\n";
190 }
191 }
192 \%drivers;
193 }
194
195 sub read_kernel_aliasmap {
196 my ($f) = @_;
197 my %drivers;
198 if (!$f || $f eq '/dev/null') {
199 $f = find { -e $_ } map { "$_/dkms-modules-info/dkms-modules.alias" } qw(. ..);
200 }
201 foreach (cat_($f)) {
202 # too bad nvidia driver doesn't list its ids...
203 next if !/alias pci.* fglrx/;
204 if (/alias pci:v0000(....)d0000(....)sv/) {
205 my ($id1, $id2) = (lc($1), lc($2));
206 $drivers{ join '', map { /(....)$/ } $id1, $id2, '0xffff', '0xffff' } = [ $ati_driver ];
207 }
208 }
209 \%drivers;
210 }
211
212
213 sub read_kernel_pcimap {
214 my ($f) = @_;
215 my (%drivers, %driver_with_classes);
216 foreach (cat_($f)) {
217 chomp;
218 next if /^#/ || /^\s*$/;
219 my ($module, $id1, $id2, $subid1, $subid2) = split;
220 next if $module eq 'pci';
221 ($subid1, $subid2) = ("ffff", "ffff") if hex($subid1) == 0 && hex($subid2) == 0;
222 if ($id2 =~ /ffff$/ && $id1 !~ /ffff$/) {
223 # $driver_with_classes{$id1} = [ $module, '' ];
224 $driver_with_classes{join '', map { /(....)$/ } $id1, $id2, $subid1, $subid2} = [ $module, '' ];
225 } else {
226 $drivers{join '', map { /(....)$/ } $id1, $id2, $subid1, $subid2} = [ $module, '' ];
227 }
228 }
229 \%drivers, \%driver_with_classes;
230 }
231
232 sub read_kernel_usbmap {
233 my ($f) = @_;
234 my %drivers;
235 foreach (cat_($f)) {
236 chomp;
237 next if /^#/ || /^\s*$/;
238 my ($module, $flag, $id1, $id2) = split;
239 hex($flag) == 3 or next;
240 $drivers{join '', map { /(....)$/ } $id1, $id2, "ffff", "ffff"} = [ $module, '' ];
241 }
242 \%drivers;
243 }
244
245 sub read_pciids {
246 my ($f) = @_;
247 my %drivers;
248 my ($id1, $id2, $class, $line, %class);
249 foreach (cat_($f)) {
250 chomp; $line++;
251 next if /^#/ || /^;/ || /^\s*$/;
252 if (/^C\s/) {
253 last;
254 } elsif (my ($subid1, $subid2, $text) = /^\t\t(\S+)\s+(\S+)\s+(.+)/) {
255 $text =~ s/\t/ /g;
256 $id1 && $id2 or die "$f:$line: unexpected device\n";
257 $drivers{sprintf qq(%04x%04x%04x%04x), hex($id1), hex($id2), hex($subid1), hex($subid2)} = [ "unknown", "$class|$text" ];
258 } elsif (/^\t(\S+)\s+(.+)/) {
259 ($id2, $text) = ($1, $2);
260 $text =~ s/\t/ /g;
261 $id1 && $id2 or die "$f:$line: unexpected device\n";
262 $drivers{sprintf qq(%04x%04xffffffff), hex($id1), hex($id2)} = [ "unknown", "$class|$text" ];
263 } elsif (/^(\S+)\s+(.+)/) {
264 $id1 = $1;
265 $class = $class{$2} || $2;
266 $class =~ s/(Advanced Micro Devices) \[AMD\]/$1/;
267 } else {
268 warn "bad line: $_\n";
269 }
270 }
271 \%drivers;
272 }
273
274 sub read_pcilst {
275 my ($f) = @_;
276 my %drivers;
277 my ($class, $line, %class);
278 foreach (cat_($f)) {
279 chomp; $line++;
280 next if /^#/ || /^;/ || /^\s*$/;
281 if (/^\t\S/) {
282 my ($id, undef, $module, $text) = split ' ', $_, 4 or die "bad line: $_\n";
283 $text =~ s/\t/ /g;
284 $module = "unknown" if dummy_module($module);
285 $drivers{"${id}ffffffff"} = [ $module, "$class|$text" ];
286 } elsif (/^(\S+)\s+(.*)/) {
287 $class = $class{$2} || $2;
288 } else {
289 die "bad line: $_\n";
290 }
291 }
292 \%drivers;
293 }
294
295 sub read_pcitablepm {
296 my ($f) = @_;
297 eval cat_($f);
298 my %drivers;
299
300 %pci_probing::pcitable::ids or die;
301 while (my ($k, $v) = each %pci_probing::pcitable::ids) {
302 $drivers{sprintf qq(%08xffffffff), $k >> 32} = [ $v->[1], $v->[0] ];
303 }
304 \%drivers;
305 }
306
307 sub read_hwd {
308 my ($f) = @_;
309 my %drivers;
310 foreach (cat_($f)) {
311 next if /^\s*#/;
312 chomp;
313 my ($id1, $id2, $_class, $module, $_undef, $descr) = /(....):(....)\s+(\S+)\s+(\S+)(\s+(.*))/ or next;
314 $drivers{"$id1${id2}ffffffff"} = [ $module, $descr ];
315 }
316 \%drivers;
317 }
318
319 sub read_hwinfo_x11 {
320 my ($f) = @_;
321
322 my (%drivers, %e, %vendors, $line);
323 foreach (cat_($f)) {
324 $line++;
325 s/\s*$//;
326 if (my ($add, $name, $val) = /^([ &])(\w+)\.id\s+(.*)/) {
327 if (!$add) {
328 warn "read_hwinfo_x11:$line: unused %e\n" if %e;
329 %e = ();
330 }
331 if ($val =~ /^pci\s+0x([0-9a-f]{4})/i) {
332 $val = hex $1;
333 } else {
334 warn "read_hwinfo_x11:$line: weird value $val\n";
335 }
336 $e{$name} = $val;
337 } elsif (/^\+vendor\.name\s+(.*)/) {
338 $vendors{$e{vendor}} = $1;
339 } elsif (/^\+(?:sub)?device\.name\s+(.*)/) {
340 $e{name} = $1;
341 } elsif (my ($driver) = /^\+driver\.xfree\s+(.*)/) {
342 if (exists $e{vendor} && exists $e{device}) {
343 my $vendor = $vendors{$e{vendor}};
344 my $module = $driver =~ /^4\|(\w+)/ ? "Driver:$1" : "Card:$driver";
345 $drivers{sprintf qq(%04x%04x%04x%04x), $e{vendor}, $e{device},
346 $e{subvendor} || 0xffff, $e{subdevice} || 0xffff} = [ $module, "$vendor|$e{name}" ];
347 } else {
348 warn "read_hwinfo_x11:$line: $driver but no vendor or no device\n";
349 }
350 } elsif (/^$/) {
351 %e = ();
352 } elsif (/^\+driver\.xfree\.config/) {
353 # drop
354 } else {
355 warn "read_hwinfo_x11:$line: unknown line $_\n";
356 }
357 }
358 \%drivers;
359 }
360
361 sub read_begent_pcids_htm {
362 my ($f) = @_;
363 my %drivers;
364 my $F;
365 open $F, $f or die "can't open $f\n";
366
367 # drop until TBODY
368 local $_;
369 while (<$F>) { last if m|<TBODY>| }
370
371 my $get_one = sub { map { scalar <$F> } 1 .. 6 };
372 my $from_h = sub {
373 local $_ = lc $_[0];
374 /([0-9a-g]{4})h/ or die "$.: bad number $_\n";
375 $1;
376 };
377
378 # drop first line
379 $get_one->();
380
381 my ($cur_vendor, $cur_vendor_descr, $cur_id);
382
383 while (1) {
384 my ($tr, $vendor, $device, $sub, $text, $tr2) = map { m|<td>(.*)</td>| ? $1 : $_ } $get_one->();
385 last if $tr =~ m|</TBODY>|;
386 $tr =~ m|<tr>| or die "$f:$.: bad <tr> line $tr\n";
387 $tr2 =~ m|</tr>| or die "$f:$.: bad </tr> line $tr2\n";
388
389 if ($vendor) {
390 $device eq '-' && $sub eq '-' or die "$f:$.: bad vendor line\n";
391 $cur_vendor = $vendor;
392 ($cur_vendor_descr) = $text =~ m|<b>(.*)</b>| or die "$f:$.: vendor descr not bold\n";
393 } else {
394 $cur_id = $device || $cur_id;
395 my $sub_t =
396 $sub ? do {
397 $sub =~ /^rev / and next; # ignoring "rev " thingy
398 if ($sub =~ /^(.....)$/) {
399 'ffff' . $from_h->($sub);
400 } else {
401 my ($s1, $s2) = $sub =~ /^(....)(.....)$/ or die "$f:$.: bad subid $sub\n";
402 $from_h->($s2) . $from_h->($s1 . 'h');
403 }
404 } : 'ffffffff';
405
406 $drivers{$from_h->($cur_vendor) . $from_h->($cur_id) . $sub_t} = [ 'unknown', "$cur_vendor_descr|$text" ];
407 }
408 }
409 \%drivers;
410 }
411
412 sub read_nvidia_readme {
413 my ($f) = @_;
414 my %drivers;
415 my $section;
416 my $card = $ENV{NVIDIA_CARD} ? $ENV{NVIDIA_CARD} : "NVIDIA_UNKNOWN";
417 foreach (cat_($f)) {
418 chomp;
419 last if $section > 3;
420 if (!($section % 2)) {
421 next unless /^\s+NVIDIA GPU product\s+Device PCI ID/;
422 $section++;
423 next;
424 }
425 if (/^\s*$/) {
426 $section++;
427 next;
428 }
429 next if /^\s+-+[\s-]+$/;
430 my ($description, $id, $subid) = /^\s+(.+?)\s+0x(....)(?: 0x(....))?/;
431 $id = "10de" . lc($id);
432 $subid = $subid ? "10de" . lc($subid) : "ffffffff";
433 $drivers{$id . $subid} = [ "Card:$card", $description ];
434 }
435 \%drivers;
436 }
437
438 sub read_fglrxko_pci_ids_h {
439 my ($f) = @_;
440 my %drivers;
441 foreach (cat_($f)) {
442 chomp;
443 my ($id) = /^\s+FGL_ASIC_ID\(0x(....)\)/ or next;
444 $drivers{"1002" . lc($id) . "ffffffff"} = [ $ati_driver_vesa, 'unknown' ];
445 }
446 \%drivers;
447 }
448
449 sub read_rhd_id_c {
450 my ($f) = @_;
451 my %drivers;
452 foreach (cat_($f)) {
453 chomp;
454 my ($id, $description) = /^\s+RHD_DEVICE_MATCH\(\s*0x(....).*\/\* (.*)\*\// or next;
455 $drivers{"1002" . lc($id) . "ffffffff"} = [ $ati_rhd_only, $description ];
456 }
457 \%drivers;
458 }
459
460 sub read_ati_pciids_csv {
461 my ($f) = @_;
462 my %drivers;
463 foreach (cat_($f)) {
464 chomp;
465 my ($id, $description) = /^"0x(....)",.*,(?:"([^,]*)")?$/ or next;
466 $drivers{"1002" . lc($id) . "ffffffff"} = [ $ati_driver, $description ];
467 }
468 \%drivers;
469 }
470
471 # write in RedHat's pcitable old format (mdk one)
472 sub write_pcitable {
473 my ($drivers) = @_;
474 foreach (sort keys %$drivers) {
475 print to_string($_, $drivers->{$_}), "\n";
476 }
477 }
478
479
480 sub merge_entries_with_wildcards {
481 my ($drivers, $classes) = @_;
482 foreach (keys %$classes) {
483 my ($vendor, $id, $subvendor, $subid);
484 next unless ($vendor, $id, $subvendor, $subid) = /^([0-9a-f]{4,4})([0-9a-f]{4,4})/;
485
486 # handle PCI_ANY_ID as PCI device ID:
487 if ($vendor !~ /ffff$/ && $id =~ /ffff$/) {
488 foreach my $old (keys %$drivers) {
489 next if $old !~ /^$vendor/ || $drivers->{$old}[0] ne 'unknown';
490 # blacklist AGP for now;
491 next if $classes->{$_}[0] =~ /agp/;
492 # the following test would be better but still generates some wrong entries (the only real check is to check
493 # PCI_CAP_ID_AGP at probing time):
494 # next if $classes->{$_}[0] =~ /-agp/ && $drivers->{$old}[1] !~ /Bridge|Controller|Host/i;
495 $drivers->{$old}[0] = $classes->{$_}[0]; # if $drivers->{$old}[0] eq "unknown";
496 }
497 }
498 }
499 }
500
501 sub merge {
502 my ($drivers, $new, $classes) = @_;
503 merge_entries_with_wildcards($drivers, $classes) if $wildcards;
504
505 foreach (keys %$new) {
506 next if $new->{$_}[0] =~ /parport_pc|i810_ng/;
507 if ($drivers->{$_}) {
508 if ($new->{$_}[0] ne "unknown") {
509 if ($drivers->{$_}[0] eq "unknown" || $force || member($new->{$_}[0], @force_modules)) {
510 $drivers->{$_}[0] = $new->{$_}[0];
511 } elsif ($drivers->{$_}[0] ne $new->{$_}[0]) {
512 my $different = 1;
513 $different = 0 if $new->{$_}[0] =~ /fb/;
514 $different = 0 if $drivers->{$_}[0] =~ /^(Card|Server):/;
515 $different = 0 if $drivers->{$_}[0] =~ /^ISDN:([^,]+)/ && $new->{$_}[0] eq $1;
516 print STDERR "different($drivers->{$_}[0] $new->{$_}[0]): ", to_string($_, $drivers->{$_}), "\n" if $different;
517 }
518 }
519 next if !$new->{$_}[1];
520 $drivers->{$_}[1] = $new->{$_}[1] if !$drivers->{$_}[1] || $drivers->{$_}[1] =~ /\|$/;
521 } else {
522 if (!/ffffffff$/ && $new->{$_}[0] eq "unknown") {
523 # keep sub-entry with major-entry module
524 # will be dropped if every subids have the same module
525 # ie. if no subids already present have a different module than the main one
526 if (/(........)/) {
527 $new->{$_}[0] = $drivers->{$1 . 'ffffffff'}[0] || "unknown"
528 if exists $drivers->{$1 . 'ffffffff'};
529 }
530 }
531
532 $drivers->{$_} = $new->{$_}
533 # don't keep sub-entries with unknown drivers
534 if $all || /ffffffff$/ || $new->{$_}[0] ne "unknown";
535 }
536 }
537 }
538
539 sub cleanup_subids {
540 my ($drivers) = @_;
541 my (%l, %m);
542 foreach (sort keys %$drivers) {
543 my ($id, $subid) = /(........)(........)/;
544 if ($l{$id}) {
545 push @{$m{$id}}, $l{$id}, $subid;
546 } else {
547 $l{$id} = $subid;
548 }
549 }
550 foreach my $id (keys %m) {
551 my %modules;
552 my $text;
553 foreach my $subid (@{$m{$id}}) {
554 my $e = $drivers->{"$id$subid"};
555 $modules{$e->[0]} = 1;
556 $text = $e->[1] if length($e->[1]) > length($text) || $subid eq 'ffffffff'; # favour previous text
557 }
558 if (keys(%modules) == 1) {
559 my ($module, undef) = each %modules;
560
561 # remove others
562 foreach my $subid (@{$m{$id}}) {
563 delete $drivers->{"$id$subid"};
564 }
565 # add a main one
566 $drivers->{$id . 'ffffffff'} = [ $module, $text ];
567 } else {
568 # print STDERR "keeping subids for $id ($text) because of ", join(", ", keys %modules), "\n";
569 }
570 }
571 }
572
573 sub error {
574 our $error = 1;
575 print STDERR "$_[0]\n";
576 }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.28