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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.30