]> git.ipfire.org Git - ipfire-2.x.git/blob - src/hwinfo/src/ids/convert_hd
HWInfo wieder eingefuegt, da mit kudzu zu viele Segmentation Faults liefert.
[ipfire-2.x.git] / src / hwinfo / src / ids / convert_hd
1 #! /usr/bin/perl
2
3 use Getopt::Long;
4 use XML::Writer;
5 use XML::Parser;
6 use IO;
7 use Dumpvalue;
8
9 sub help;
10
11 sub read_name_file;
12 sub read_driver_file;
13 sub read_id_file;
14 sub read_pcimap_file;
15 sub read_usbmap_file;
16 sub read_alias_file;
17 sub read_modinfo_file;
18 sub eisa_id;
19 sub eisa_str;
20
21 sub remove_nops;
22 sub remove_duplicates;
23 sub fix_driver_info;
24
25 sub cmp_id;
26 sub cmp_skey;
27 sub cmp_item;
28
29 sub match_id;
30 sub match_skey;
31 sub match_item;
32
33 sub join_skey;
34
35 sub split_item;
36
37 sub get_xml_data;
38 sub parse_xml_item;
39 sub parse_xml_key;
40 sub parse_xml_id;
41 sub parse_xml_id_id;
42 sub parse_xml_id_range;
43 sub parse_xml_id_mask;
44 sub parse_xml_driver;
45 sub parse_xml_driver_display;
46 sub parse_xml_driver_module;
47 sub parse_xml_driver_mouse;
48 sub parse_xml_driver_xfree;
49 sub parse_xml_pair;
50 sub parse_xml_cdata;
51 sub idstr2value;
52
53 sub dump2ids;
54 sub dump2xml;
55 sub dump_xml_item;
56 sub dump_xml_names;
57 sub dump_xml_drivers;
58 sub id2xml;
59
60 sub hd_dtd;
61 sub hd_dtd_internal;
62
63 $dump = new Dumpvalue();
64
65 (
66 $he_other, $he_bus_id, $he_baseclass_id, $he_subclass_id, $he_progif_id,
67 $he_vendor_id, $he_device_id, $he_subvendor_id, $he_subdevice_id, $he_rev_id,
68 $he_bus_name, $he_baseclass_name, $he_subclass_name, $he_progif_name,
69 $he_vendor_name, $he_device_name, $he_subvendor_name, $he_subdevice_name,
70 $he_rev_name, $he_serial, $he_driver, $he_requires,
71 $he_nomask,
72 $he_driver_module_insmod, $he_driver_module_modprobe,
73 $he_driver_module_config, $he_driver_xfree, $he_driver_xfree_config,
74 $he_driver_mouse, $he_driver_display, $he_driver_any
75 ) = ( 0 .. 100 );
76 $he_class_id = $he_nomask;
77
78 @ent_names = (
79 "other", "bus.id", "baseclass.id", "subclass.id", "progif.id",
80 "vendor.id", "device.id", "subvendor.id", "subdevice.id", "rev.id",
81 "bus.name", "baseclass.name", "subclass.name", "progif.name",
82 "vendor.name", "device.name", "subvendor.name", "subdevice.name",
83 "rev.name", "serial", "driver", "requires",
84 "class.id", "driver.module.insmod", "driver.module.modprobe",
85 "driver.module.config", "driver.xfree", "driver.xfree.config",
86 "driver.mouse", "driver.display", "driver.any"
87 );
88 @ent_values{@ent_names} = ( 0 .. 100 );
89
90 @xml_names = (
91 "other", "bus", "baseclass", "subclass", "progif",
92 "vendor", "device", "subvendor", "subdevice", "revision",
93 "bus", "baseclass", "subclass", "progif",
94 "vendor", "device", "subvendor", "subdevice",
95 "revision", "serial", "driver", "requires"
96 );
97 @xml_values{@xml_names} = ( 0 .. 100 );
98
99 ( $tag_none, $tag_pci, $tag_eisa, $tag_usb, $tag_special, $tag_pcmcia ) = ( 0 .. 5 );
100
101 @tag_name = ( "", "pci", "eisa", "usb", "special", "pcmcia" );
102 @tag_values{@tag_name} = ( 0 .. 5 );
103 $tag_values{none} = 0;
104
105 ( $flag_id, $flag_range, $flag_mask, $flag_string, $flag_regexp ) = ( 0 .. 4 );
106 $flag_cont = 8;
107
108 # map usb modules to device classes
109 %usbmod2class = (
110 'ov511' => [ 0x10f, 0 ],
111 'pwc' => [ 0x10f, 0 ],
112 'hpusbscsi' => [ 0x10c, 0 ],
113 'microtek' => [ 0x10c, 0 ],
114 'scanner' => [ 0x10c, 0 ]
115 );
116
117
118 # options
119 $opt_write_ids = 1;
120 $opt_write_xml = 0;
121 $opt_sort_ids = 0;
122 $opt_sort_reverse = 0;
123 $opt_sort_random = 0; # for testing
124 $opt_split = 0;
125 $opt_with_source = 0;
126 $opt_fix_driver = 1;
127 $opt_help = 0;
128 $opt_internal_dtd = 0;
129
130 $opt_ok = GetOptions(
131 'ids' => \$opt_write_ids,
132 'no-ids' => sub { $opt_write_ids = 0 },
133 'xml' => \$opt_write_xml,
134 'no-xml' => sub { $opt_write_xml = 0 },
135 'sort' => \$opt_sort,
136 'reverse' => \$opt_sort_reverse,
137 'random' => \$opt_sort_random,
138 'split' => \$opt_split,
139 'with-source' => \$opt_with_source,
140 'fix-driver' => \$opt_fix_driver,
141 'no-fix-driver' => sub { $opt_fix_driver = 0 },
142 'internal-dtd' => \$opt_internal_dtd,
143 'help' => \&help
144 ) ;
145
146 for $f (@ARGV) {
147 if(open F, $f) {
148 @f = (<F>);
149 close F;
150
151 # file format check
152
153 undef $format;
154
155 for (@f) {
156 if(/^\s*\<\?xml\s/) {
157 $format = 'xml';
158 last;
159 }
160
161 if(/^#\s+pci\s+module\s+vendor\s+device\s+subvendor\s+subdevice\s+class\s+class_mask\s+driver_data\s*$/) {
162 $format = 'pcimap';
163 last;
164 }
165
166 if(/^#\s+usb\s+module\s+match_flags\s+idVendor\s+idProduct\s+/) {
167 $format = 'usbmap';
168 last;
169 }
170
171 if(/^\s*alias\s+(pci|pnp|usb):\S+\s+\S+$/) {
172 $format = 'alias';
173 last;
174 }
175
176 if(/^\s*alias:\s+(pci|pnp|usb):\S+\s*$/) {
177 $format = 'modinfo';
178 last;
179 }
180
181 }
182
183 if(!$format) {
184 $i = join "|", map "\Q$_", @ent_names;
185 for (@f) {
186 if(/^\s*[+&|]?($i)\s/) {
187 $format = 'ids';
188 last;
189 }
190 }
191 }
192
193 if(!$format) {
194 for (@f) {
195 if(/^\t[a-z]\s/) {
196 $format = 'drivers';
197 last;
198 }
199 }
200 }
201
202 $format = 'names' if !$format;
203
204 if($format eq 'names') {
205
206 print STDERR "====== \"$f\": name info ======\n";
207 read_name_file $f, \@f;
208
209 }
210 elsif($format eq 'drivers') {
211
212 print STDERR "====== \"$f\": driver info ======\n";
213 read_driver_file $f, \@f;
214
215 }
216 elsif($format eq 'xml') {
217
218 print STDERR "====== \"$f\": xml info ======\n";
219 $xmlp = new XML::Parser(Style => 'Tree', ParseParamEnt => 1);
220 get_xml_data $xmlp->parsefile($f);
221
222 }
223 elsif($format eq 'ids') {
224
225 print STDERR "====== \"$f\": id info ======\n";
226 read_id_file $f, \@f;
227
228 }
229 elsif($format eq 'pcimap') {
230
231 print STDERR "====== \"$f\": pcimap info ======\n";
232 read_pcimap_file $f, \@f;
233
234 }
235 elsif($format eq 'usbmap') {
236
237 print STDERR "====== \"$f\": usbmap info ======\n";
238 read_usbmap_file $f, \@f;
239
240 }
241 elsif($format eq 'alias') {
242
243 print STDERR "====== \"$f\": alias info ======\n";
244 read_alias_file $f, \@f;
245
246 }
247 elsif($format eq 'modinfo') {
248
249 print STDERR "====== \"$f\": module info ======\n";
250 read_modinfo_file $f, \@f;
251
252 }
253 }
254 else {
255 die "$f: $!\n"
256 }
257 }
258
259 print STDERR "removing unnecessary items\n";
260 remove_nops;
261
262 print STDERR "got ${\scalar @hd} items\n";
263
264 if($opt_fix_driver) {
265 fix_driver_info;
266 }
267
268 if($opt_split) {
269 print STDERR "splitting items\n";
270 for (@hd) {
271 push @hd_new, split_item($_);
272 }
273 @hd = @hd_new;
274 undef @hd_new;
275 }
276
277 if($opt_sort_ids) {
278 print STDERR "sorting\n";
279 if($opt_sort_random) {
280 @hd = sort { $cmp_item_cnt++, rand() <=> rand() } @hd;
281 }
282 elsif($opt_sort_reverse) {
283 @hd = sort { cmp_item $b, $a } @hd;
284 }
285 else {
286 @hd = sort { cmp_item $a, $b } @hd;
287 }
288 }
289
290 if($opt_write_ids) {
291 print STDERR "writing \"hd.ids\"\n";
292 dump2ids;
293 }
294
295 if($opt_write_xml) {
296 print STDERR "writing \"hd.xml\"\n";
297 dump2xml;
298 }
299
300 print STDERR "cmps: $cmp_item_cnt\n" if $cmp_item_cnt;
301
302 # $dump->dumpValue( \@hd );
303
304
305 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
306
307 sub help
308 {
309 print STDERR
310 "Usage: convert_hd [options] files\n" .
311 "Convert various hardware info to libhd/hwinfo internal format or to XML.\n" .
312 " --ids write internal format (default) to \"hd.ids\"\n" .
313 " --no-ids do not write internal format\n" .
314 " --xml write XML to \"hd.xml\", DTD to \"hd.dtd\"\n" .
315 " --no-xml do not write XML (default)\n" .
316 " --with-source add comment to each item indicating info source\n" .
317 " --internal-dtd generate internal dtd\n\n" .
318 " Note: for more sophisticated operations on hardware data use check_hd.\n";
319
320 exit 0;
321 }
322
323
324 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
325 sub num
326 {
327 return $_[0] =~ /^0/ ? oct $_[0] : return $_[0] + 0;
328 }
329
330
331 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
332 #
333 # read file with name/class info
334 #
335 # (either pciutils or SaX/SaX2 format)
336 #
337
338 sub read_name_file
339 {
340 my ( $file_name, $file, $line, $sax_version, $tag, $id, $val, $ent );
341 my ( @id0, @id1, @id2, @id3, @id4, $raw, $opt, $ext, $srv, $str );
342 local $_;
343
344 my $rnf_add_id0 = sub
345 {
346 my ( $id0, $name0, $ent_id0, $ent_name0, $id, $val );
347
348 # note: $tag belongs to read_name_file()
349 ( $ent_id0, $ent_name0, $tag, $id0, $name0 ) = @_;
350
351 $ent = $ent_id0;
352
353 @id0 = ( $flag_id, $tag, $id0 );
354 undef @id1; undef @id2; undef @id3;
355
356 $id->[$ent_id0] = [ @id0 ];
357 $val->[$ent_name0] = [ $flag_string, $name0 ];
358
359 push @hd, [ "$file_name($line)", [ $id ], $val ];
360 };
361
362 my $rnf_add_bus = sub
363 {
364 $rnf_add_id0->($he_bus_id, $he_bus_name, 0, @_);
365 };
366
367 my $rnf_add_baseclass = sub
368 {
369 $rnf_add_id0->($he_baseclass_id, $he_baseclass_name, 0, @_);
370 };
371
372 my $rnf_add_vendor = sub
373 {
374 $rnf_add_id0->($he_vendor_id, $he_vendor_name, @_);
375 };
376
377 my $rnf_add_subdevice = sub
378 {
379 my ( $id2, $id3, $range, $name, $class, $id, $val );
380
381 ( $id2, $id3, $range, $name, $class ) = @_;
382
383 @id2 = ( $flag_id, $tag, $id2 );
384 @id3 = ( $flag_id, $tag, $id3 );
385 $id3[3] = $range if defined $range;
386
387 if($ent == $he_device_id || $ent == $he_subdevice_id) {
388 $ent = $he_subdevice_id;
389
390 $id->[$he_vendor_id] = [ @id0 ];
391 $id->[$he_device_id] = [ @id1 ];
392 $id->[$he_subvendor_id] = [ @id2 ];
393 $id->[$he_subdevice_id] = [ @id3 ];
394 $val->[$he_subdevice_name] = [ $flag_string, $name ];
395 if(defined $class) {
396 $val->[$he_baseclass_id] = [ $flag_id, $tag_none, $class >> 8 ];
397 $val->[$he_subclass_id] = [ $flag_id, $tag_none, $class & 0xff ];
398 }
399 }
400 else {
401 die "oops $file_name($line): subdevice id expected\n";
402 }
403
404 push @hd, [ "$file_name($line)", [ $id ], $val ];
405 };
406
407 ( $file_name, $file ) = @_;
408
409 $line = 0;
410 undef $sax_version;
411
412 for (@$file) {
413 $line++;
414 chomp;
415 s/\s*$//;
416 next if /^\s*[#;]/;
417 next if /^$/;
418
419 # SaX Identity file
420 if(/^NAME=(.+?)§DEVICE=(.+?)§VID=0x([0-9a-fA-F]+?)§DID=0x([0-9a-fA-F]+?)§SERVER=([^§]+)(§EXT=([^§]*))?(§OPT=([^§]*))?(§RAW=([^§]*))?$/) {
421 # 1 2 3 4 5 6 7 8 9 10 11
422
423 $rnf_add_vendor->($tag_pci, hex($3), $1);
424
425 @id0 = ( $flag_id, $tag, hex($3) );
426 @id1 = ( $flag_id, $tag, hex($4) );
427 @id3 = ( $flag_string, $2 );
428
429 $id = [];
430 $val = [];
431
432 $id->[$he_vendor_id] = [ @id0 ];
433 $id->[$he_device_id] = [ @id1 ];
434 $val->[$he_device_name] = [ @id3 ];
435
436 push @hd, [ "$file_name($line)", [ $id ], $val ];
437
438 ( $srv, $ext, $opt, $raw ) = ( $5, $7, $9, $11 );
439 $sax_tmp = $srv =~ /^3DLABS|MACH64|P9000|RUSH|S3|SVGA|TGA$/ ? 1 : 2;
440 $sax_version = $sax_tmp unless defined $sax_version;
441 die "line has SaX$sax_tmp format (expected SaX$sax_version): $file_name($line)\n" if $sax_tmp != $sax_version;
442
443 $id = [];
444 $val = [];
445
446 $id->[$he_vendor_id] = [ @id0 ];
447 $id->[$he_device_id] = [ @id1 ];
448
449 if($opt) {
450 $str = join "|", ( $sax_version == 1 ? 3 : 4, $srv, undef, undef, $ext, $opt );
451 }
452 elsif($ext) {
453 $str = join "|", ( $sax_version == 1 ? 3 : 4, $srv, undef, undef, $ext );
454 }
455 else {
456 $str = join "|", ( $sax_version == 1 ? 3 : 4, $srv );
457 }
458
459 @id4 = ( "x\t$str" );
460 if($raw) {
461 for $str (split /,/, $raw) { $id4[0] .= "\x00X\t$str" }
462 }
463
464 $val->[$he_driver] = [ $flag_string, @id4 ];
465
466 push @hd, [ "$file_name($line)", [ $id ], $val ];
467 }
468
469 elsif(/^B\s+([0-9a-fA-F]+)\s+(.*?)\s*$/) {
470
471 $rnf_add_bus->(hex($1), $2);
472
473 }
474
475 elsif(/^C\s+([0-9a-fA-F]+)\s+(.*?)\s*$/) {
476
477 $rnf_add_baseclass->(hex($1), $2);
478
479 }
480
481 elsif(/^([0-9a-fA-F]{4})(\s+(.*?))?\s*$/) {
482
483 $rnf_add_vendor->($tag_pci, hex($1), $3);
484
485 }
486
487 elsif(/^u([0-9a-fA-F]{4})(\s+(.*?))?\s*$/) {
488
489 $rnf_add_vendor->($tag_usb, hex($1), $3);
490
491 }
492
493 elsif(/^s([0-9a-fA-F]{4})(\s+(.*?))?\s*$/) {
494
495 $rnf_add_vendor->($tag_special, hex($1), $3);
496
497 }
498
499 elsif(/^([A-Z_@]{3})(\s+(.*?))?\s*$/) {
500
501 $rnf_add_vendor->($tag_eisa, eisa_id($1), $3);
502
503 }
504
505 elsif(/^\t([0-9a-fA-F]{1,4})(\+([0-9a-fA-F]+))?(\.([0-9a-fA-F]+))?(\s+(.*?))?\s*$/) {
506
507 $range = $3 ? hex($3) : undef;
508 $class = $5 ? hex($5) : undef;
509
510 @id1 = ( $flag_id, $tag, hex($1) );
511 $id1[3] = $range if defined $range;
512 undef @id2; undef @id3;
513
514 $id = [];
515 $val = [];
516
517 if($ent == $he_baseclass_id || $ent == $he_subclass_id) {
518 $ent = $he_subclass_id;
519
520 $id->[$he_baseclass_id] = [ @id0 ];
521 $id->[$he_subclass_id] = [ @id1 ];
522 $val->[$he_subclass_name] = [ $flag_string, $7 ];
523 }
524 elsif($ent == $he_vendor_id || $ent == $he_device_id || $ent == $he_subdevice_id) {
525 $ent = $he_device_id;
526
527 $id->[$he_vendor_id] = [ @id0 ];
528 $id->[$he_device_id] = [ @id1 ];
529 $val->[$he_device_name] = [ $flag_string, $7 ];
530 if(defined $class) {
531 $val->[$he_baseclass_id] = [ $flag_id, $tag_none, $class >> 8 ];
532 $val->[$he_subclass_id] = [ $flag_id, $tag_none, $class & 0xff ];
533 }
534 }
535 else {
536 die "oops $file_name($line): device id expected\n";
537 }
538
539 push @hd, [ "$file_name($line)", [ $id ], $val ];
540
541 }
542
543 elsif($ent == $he_subclass_id && /^\t\t([0-9a-fA-F]+)\s+(.*?)\s*$/) {
544
545 @id2 = ( $flag_id, $tag, hex($1) );
546 undef @id3;
547
548 $id = [];
549 $val = [];
550
551 $id->[$he_baseclass_id] = [ @id0 ];
552 $id->[$he_subclass_id] = [ @id1 ];
553 $id->[$he_progif_id] = [ @id2 ];
554 $val->[$he_progif_name] = [ $flag_string, $2 ];
555
556 push @hd, [ "$file_name($line)", [ $id ], $val ];
557
558 }
559
560 elsif(/^\t\t([0-9a-fA-F]{4})\s+([0-9a-fA-F]{4})(\+([0-9a-fA-F]+))?(\.([0-9a-fA-F]+))?(\s+(.*?))?\s*$/) {
561
562 $rnf_add_subdevice->(hex($1), hex($2), $4 ? hex($4) : undef, $8, $6 ? hex($6) : undef);
563
564 }
565
566 elsif(/^\t\t([A-Z_@]{3})\s+([0-9a-fA-F]{4})(\+([0-9a-fA-F]+))?(\.([0-9a-fA-F]+))?(\s+(.*?))?\s*$/) {
567
568 $rnf_add_subdevice->(eisa_id($1), hex($2), $4 ? hex($4) : undef, $8, $6 ? hex($6) : undef);
569
570 }
571
572 elsif(/^\t\t([0-9a-fA-F]{4})([0-9a-fA-F]{4})\s+(.*?)\s*$/) {
573
574 # NOTE: subvendor & subdevice ids are reversed!
575 $rnf_add_subdevice->(hex($2), hex($1), undef, $3);
576
577 }
578
579 else {
580 die "invalid line: $file_name($line)\n";
581 }
582 }
583 }
584
585
586 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
587 #
588 # read file with driver info
589 #
590
591 sub read_driver_file
592 {
593 my ( $line, @drv, $file, $file_name, $drv_type, $tag );
594 local $_;
595
596 my $rdf_save_drv = sub
597 {
598 if($drv_type) {
599 push @hd, [ @drv ] if defined @drv;
600 @drv = ( "$file_name($line)" );
601 $drv[2][$he_driver] = [ $flag_string ];
602 $drv_type = undef;
603 }
604 };
605
606 my $rdf_add_id = sub
607 {
608 my ( $tag, $id0, $id1, $range1, $id2, $id3, $range3, $id );
609
610 ( $tag, $id0, $id1, $range1, $id2, $id3, $range3 ) = @_;
611
612 $rdf_save_drv->();
613
614 $id = [];
615
616 @id0 = ( $flag_id, $tag, $id0 );
617 @id1 = ( $flag_id, $tag, $id1 );
618 $id1[3] = $range1 if defined $range1;
619
620 $id->[$he_vendor_id] = [ @id0 ];
621 $id->[$he_device_id] = [ @id1 ];
622
623 if(defined $id2) {
624 @id2 = ( $flag_id, $tag, $id2 );
625 @id3 = ( $flag_id, $tag, $id3 );
626 $id3[3] = $range3 if defined $range3;
627
628 $id->[$he_subvendor_id] = [ @id2 ];
629 $id->[$he_subdevice_id] = [ @id3 ];
630 }
631 push @{$drv[1]}, $id;
632 };
633
634 ( $file_name, $file ) = @_;
635
636 $drv_type = 1;
637
638 for (@$file) {
639 $line++;
640 chomp;
641 s/\s*$//;
642 next if /^[#;]/;
643 next if /^$/;
644
645 if(/^([us]?)([0-9a-fA-F]{4})\s+([0-9a-fA-F]{4})(\+([0-9a-fA-F]+))?\s*$/) {
646
647 $tag = $tag_pci;
648 $tag = $tag_usb if $1 eq 'u';
649 $tag = $tag_special if $1 eq 's';
650
651 $rdf_add_id->($tag, hex($2), hex($3), $5 ? hex($5) : undef);
652
653 }
654
655 elsif(/^([A-Z_@]{3})\s+([0-9a-fA-F]{4})(\+([0-9a-fA-F]+))?\s*$/) {
656
657 $rdf_add_id->($tag_eisa, eisa_id($1), hex($2), $4 ? hex($4) : undef);
658
659 }
660
661 elsif(/^([us]?)([0-9a-fA-F]{4})\s+([0-9a-fA-F]{4})(\+([0-9a-fA-F]+))?\s+([us]?)([0-9a-fA-F]{4})\s+([0-9a-fA-F]{4})(\+([0-9a-fA-F]+))?\s*$/) {
662
663 $tag = $tag_pci;
664 $tag = $tag_usb if $1 eq 'u';
665 $tag = $tag_special if $1 eq 's';
666
667 $rdf_add_id->($tag, hex($2), hex($3), $5 ? hex($5) : undef, hex($7), hex($8), $10 ? hex($10) : undef);
668
669 }
670
671 elsif(/^([A-Z_@]{3})\s+([0-9a-fA-F]{4})(\+([0-9a-fA-F]+))?\s+([A-Z_@]{3})\s+([0-9a-fA-F]{4})(\+([0-9a-fA-F]+))?\s*$/) {
672
673 $rdf_add_id->($tag_eisa, eisa_id($1), hex($2), $4 ? hex($4) : undef, eisa_id($5), hex($6), $8 ? hex($8) : undef);
674
675 }
676
677 elsif(/^\t([a-z])\s+(.*?)\s*$/) {
678
679 push @{$drv[2][$he_driver]}, "$1\t$2";
680 $drv_type = $1;
681
682 }
683
684 elsif($drv_type && /^\t\t\s*(.*)$/) {
685
686 $drv_type = "X" if $drv_type eq "x";
687 $drv_type = "M" if $drv_type eq "m";
688 $drv[2][$he_driver][-1] .= "\x00$drv_type\t$1";
689
690 }
691
692 else {
693 die "invalid line: $file_name($line)\n";
694 }
695 }
696
697 $rdf_save_drv->();
698 }
699
700
701 sub num
702 {
703 return $_[0] =~ /^0/ ? oct $_[0] : return $_[0] + 0;
704 }
705
706 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
707 #
708 # read file with id info
709 #
710
711 sub read_id_file
712 {
713 my ( $line, $file, $file_name, $tag, $pre, $fields, @item, @id, $state, $keyid );
714 my ( $is_id, $i );
715 local $_;
716
717 my $rif_save_item = sub
718 {
719 if(@item > 1) {
720 push @hd, [ @item ];
721 }
722 @item = ( "$file_name($line)" );
723 };
724
725 # parse id field
726 my $str2id = sub
727 {
728 my ($val, $id, $tag, $mask, $range, @id);
729
730 $val = shift;
731
732 if($val =~ s/^(${\join '|', @tag_name})\s+//o) {
733 die "internal oops: $file_name($line)\n" unless exists $tag_values{$1};
734 $tag = $tag_values{$1};
735 }
736 else {
737 $tag = 0;
738 }
739
740 if($val =~ /^\s*(\S+)\s*([&+])\s*(\S+)\s*$/) {
741 $id = $1;
742 if($2 eq "+") {
743 $range = $3;
744 }
745 else {
746 $mask = $3;
747 }
748 }
749 else {
750 $id = $val;
751 }
752
753 if(defined $range) {
754 if($range =~ /^(0x[0-9a-zA-Z]+|\d+)$/) {
755 $range = num $range;
756 }
757 else {
758 die "$file_name($line): invalid range\n"
759 }
760 }
761
762 if(defined $mask) {
763 if($mask =~ /^(0x[0-9a-zA-Z]+|\d+)$/) {
764 $mask = num $mask;
765 }
766 else {
767 die "$file_name($line): invalid mask\n"
768 }
769 }
770
771 if($id =~ /^(0x[0-9a-zA-Z]+|\d+)$/) {
772 $id = num $id;
773 }
774 elsif(($tag == $tag_none || $tag == $tag_eisa) && $id =~ /^[A-Z_@]{3}$/) {
775 $id = eisa_id $id;
776 $tag = $tag_eisa;
777 }
778 else {
779 die "$file_name($line): invalid id\n"
780 }
781
782 @id = ( $flag_id, $tag, $id );
783 $id[3] = $range if defined $range;
784 $id[4] = $mask if defined $mask;
785
786 return \@id;
787 };
788
789 ( $file_name, $file ) = @_;
790
791 $fields = join "|", map "\Q$_", @ent_names;
792
793 $state = 0;
794
795 $rif_save_item->();
796
797 for (@$file) {
798 $line++;
799 chomp;
800 s/\s*$//;
801 next if /^\s*[#;]/;
802 next if /^$/;
803
804 if(/^\s*([+&|]?)($fields)\s+(.+)/) {
805 ($pre, $key, $val) = ($1, $2, $3);
806 # print ">$pre< $is_id>$key< >$val<\n";
807 die "internal oops: $file_name($line)\n" unless exists $ent_values{$key};
808 $keyid = $ent_values{$key};
809 $is_id = $keyid < $he_nomask && $key =~ /\.id$/ ? 1 : 0;
810 }
811 else {
812 die "invalid line: $file_name($line)\n";
813 }
814
815 if($pre eq "") {
816 die "invalid line: $file_name($line)\n" unless $state == 0 || $state == 2;
817 if($state == 2) {
818 $item[2] = [ @id ];
819 undef @id;
820 }
821 $rif_save_item->();
822 $state = 1;
823 }
824 elsif($pre eq "|") {
825 die "invalid line: $file_name($line)\n" unless $state == 1;
826 push @{$item[1]}, [ @id ];
827 undef @id;
828 }
829 elsif($pre eq "&") {
830 die "invalid line: $file_name($line)\n" unless $state == 1;
831 }
832 elsif($pre eq "+") {
833 die "invalid line: $file_name($line)\n" unless $state == 1 || $state == 2;
834 if($state == 1) {
835 push @{$item[1]}, [ @id ];
836 undef @id;
837 }
838 $state = 2;
839 }
840 else {
841 die "internal oops: $file_name($line)\n";
842 }
843
844 if($is_id) {
845 $id[$keyid] = $str2id->($val);
846 }
847 elsif($keyid < $he_nomask) {
848 $id[$keyid] = [ $flag_string, $val ];
849 }
850 elsif($keyid == $he_class_id) {
851 $i = ${$str2id->($val)}[2];
852 $id[$he_baseclass_id] = [ $flag_id, $tag_none, $i >> 8 ];
853 $id[$he_subclass_id] = [ $flag_id, $tag_none, $i & 0xff ];
854 }
855 else {
856 undef $i;
857 if($keyid == $he_driver_module_insmod) {
858 $i = "i";
859 }
860 elsif($keyid == $he_driver_module_modprobe) {
861 $i = "m";
862 }
863 elsif($keyid == $he_driver_module_config) {
864 $i = "M";
865 }
866 elsif($keyid == $he_driver_xfree) {
867 $i = "x";
868 }
869 elsif($keyid == $he_driver_xfree_config) {
870 $i = "X";
871 }
872 elsif($keyid == $he_driver_mouse) {
873 $i = "p";
874 }
875 elsif($keyid == $he_driver_display) {
876 $i = "d";
877 }
878 elsif($keyid == $he_driver_any) {
879 $i = "a";
880 }
881 else {
882 die "unhandled entry: $file_name($line)\n"
883 }
884 $val = "$i\t$val";
885 if(!defined $id[$he_driver]) {
886 $id[$he_driver] = [ $flag_string ];
887 }
888 if($i eq "X" || $i eq "M") {
889 $id[$he_driver]->[-1] .= "\x00$val"
890 }
891 else {
892 push @{$id[$he_driver]}, $val;
893 }
894 }
895 }
896
897 if($state == 2) {
898 $item[2] = [ @id ];
899 undef @id;
900 }
901
902 $rif_save_item->();
903 }
904
905
906 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
907 #
908 # read pcimap file
909 #
910
911 sub read_pcimap_file
912 {
913 my (@l, $id, $n, $key, $val, $mask);
914 local $_;
915
916 ( $file_name, $file ) = @_;
917
918 for (@$file) {
919 $line++;
920 chomp;
921 s/\s*$//;
922 next if /^\s*#/;
923 next if /^$/;
924
925 @l = split;
926
927 die "invalid line: $file_name($line)\n" unless @l == 8;
928
929 $val = [];
930
931 $val->[$he_driver] = [ $flag_string, "m\t$l[0]" ];
932
933 $key = [];
934
935 $key->[$he_vendor_id] = [ $flag_id, $tag_pci, $n ] if ($n = num $l[1]) != 0xffffffff;
936 $key->[$he_device_id] = [ $flag_id, $tag_pci, $n ] if ($n = num $l[2]) != 0xffffffff;
937 $key->[$he_subvendor_id] = [ $flag_id, $tag_pci, $n ] if ($n = num $l[3]) != 0xffffffff;
938 $key->[$he_subdevice_id] = [ $flag_id, $tag_pci, $n ] if ($n = num $l[4]) != 0xffffffff;
939
940 $n = num $l[6];
941
942 if($mask = ($n >> 16) & 0xff) {
943 $key->[$he_baseclass_id] = [ $flag_id, $tag_none, (num($l[5]) >> 16) & 0xff ];
944 if($mask != 0xff) {
945 $key->[$he_baseclass_id][4] = (~$mask & 0xff);
946 }
947 }
948
949 if($mask = ($n >> 8) & 0xff) {
950 $key->[$he_subclass_id] = [ $flag_id, $tag_none, (num($l[5]) >> 8) & 0xff ];
951 if($mask != 0xff) {
952 $key->[$he_subclass_id][4] = (~$mask & 0xff);
953 }
954 }
955
956 if($mask = $n & 0xff) {
957 $key->[$he_progif_id] = [ $flag_id, $tag_none, num($l[5]) & 0xff ];
958 if($mask != 0xff) {
959 $key->[$he_progif_id][4] = (~$mask & 0xff);
960 }
961 }
962
963 push @hd, [ "$file_name($line)", [ $key ], $val ];
964 }
965 }
966
967
968 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
969 #
970 # read usbmap file
971 #
972
973 sub read_usbmap_file
974 {
975 my (@l, $id, $n, $key, $val, $mask);
976 local $_;
977
978 ( $file_name, $file ) = @_;
979
980 for (@$file) {
981 $line++;
982 chomp;
983 s/\s*$//;
984 next if /^\s*#/;
985 next if /^$/;
986
987 @l = split;
988
989 die "invalid line: $file_name($line)\n" unless @l == 13;
990
991 next if num($l[1]) != 3; # match_flags != 3
992
993 $val = [];
994
995 $key = [];
996
997 $key->[$he_vendor_id] = [ $flag_id, $tag_usb, num($l[2]) ];
998 $key->[$he_device_id] = [ $flag_id, $tag_usb, num($l[3]) ];
999
1000 $val->[$he_driver] = [ $flag_string, "m\t$l[0]" ];
1001
1002 if($usbmod2class{$l[0]}) {
1003 $val->[$he_baseclass_id] = [ $flag_id, $tag_none, $usbmod2class{$l[0]}[0] ] if defined $usbmod2class{$l[0]}[0];
1004 $val->[$he_subclass_id] = [ $flag_id, $tag_none, $usbmod2class{$l[0]}[1] ] if defined $usbmod2class{$l[0]}[1];
1005 }
1006
1007 push @hd, [ "$file_name($line)", [ $key ], $val ];
1008 }
1009 }
1010
1011
1012 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1013 #
1014 # read alias file
1015 #
1016
1017 sub read_alias_file
1018 {
1019 my ($f, $id, $n, $key, $val, $mask, $tag, $module, $spec, $t1, $t2);
1020 local $_;
1021
1022 $f = '[0-9A-F*]+';
1023
1024 ( $file_name, $file ) = @_;
1025
1026 for (@$file) {
1027 $line++;
1028 chomp;
1029 s/\s*$//;
1030 next if /^\s*#/;
1031 next if /^$/;
1032
1033 next unless /^\s*alias\s+(pci|pnp|usb):(\S+)\s+(\S+)/;
1034
1035 $tag = $tag_pci if $1 eq 'pci';
1036 $tag = $tag_eisa if $1 eq 'pnp';
1037 $tag = $tag_usb if $1 eq 'usb';
1038
1039 $spec = $2;
1040 $module = $3;
1041
1042 $val = [];
1043
1044 $val->[$he_driver] = [ $flag_string, "m\t$module" ];
1045
1046 $key = [];
1047
1048 if($spec =~ /^v($f)d($f)sv($f)sd($f)bc($f)sc($f)i($f)$/ ) {
1049 $key->[$he_vendor_id] = [ $flag_id, $tag, hex $1 ] if $1 ne '*';
1050 $key->[$he_device_id] = [ $flag_id, $tag, hex $2 ] if $2 ne '*';
1051 $key->[$he_subvendor_id] = [ $flag_id, $tag, hex $3 ] if $3 ne '*';
1052 $key->[$he_subdevice_id] = [ $flag_id, $tag, hex $4 ] if $4 ne '*';
1053 $key->[$he_baseclass_id] = [ $flag_id, $tag_none, hex $5 ] if $5 ne '*';
1054 $key->[$he_subclass_id] = [ $flag_id, $tag_none, hex $6 ] if $6 ne '*';
1055 $key->[$he_progif_id] = [ $flag_id, $tag_none, hex $7 ] if $7 ne '*';
1056
1057 push @hd, [ "$file_name($line)", [ $key ], $val ];
1058 }
1059 elsif($spec =~ /^v($f)p($f)dl($f)dh($f)dc($f)dsc($f)dp($f)ic($f)isc($f)ip($f)$/ ) {
1060
1061 if(
1062 $3 == '*' && $4 == '*' && $5 == '*' &&
1063 $6 == '*' && $7 == '*' && $8 == '*' &&
1064 $9 == '*' && $10 == '*'
1065 ) {
1066 $key->[$he_vendor_id] = [ $flag_id, $tag, hex $1 ] if $1 ne '*';
1067 $key->[$he_device_id] = [ $flag_id, $tag, hex $2 ] if $2 ne '*';
1068
1069 push @hd, [ "$file_name($line)", [ $key ], $val ];
1070 }
1071 }
1072 elsif($spec =~ /^[c|d](\S{3})([0-9a-fA-FX]{4})/ ) {
1073 $t1 = $1;
1074 $t2 = $2;
1075
1076 if($t1 =~ /[\@A-Z\[\\\]\^_]{3}/ && $t2 ne 'XXXX') {
1077 $key->[$he_vendor_id] = [ $flag_id, $tag, eisa_id $t1 ];
1078 $key->[$he_device_id] = [ $flag_id, $tag, hex $t2 ];
1079
1080 push @hd, [ "$file_name($line)", [ $key ], $val ];
1081 }
1082 }
1083 else {
1084 die "invalid line: $file_name($line)\n"
1085 }
1086 }
1087 }
1088
1089
1090 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1091 #
1092 # read modinfo data
1093 #
1094
1095 sub read_modinfo_file
1096 {
1097 my ($f, $id, $n, $key, $val, $mask, $tag, $module, $spec, $t1, $t2);
1098 local $_;
1099
1100 $f = '[0-9A-F*]+';
1101
1102 ( $file_name, $file ) = @_;
1103
1104 for (@$file) {
1105 $line++;
1106 chomp;
1107 s/\s*$//;
1108 next if /^\s*#/;
1109 next if /^$/;
1110
1111 if(m#([^/]+)\.ko:$#) {
1112 $module = $1;
1113 next;
1114 }
1115
1116 next unless /^\s*alias:\s+(pci|pnp|usb):(\S+)\s*$/;
1117
1118 $tag = $tag_pci if $1 eq 'pci';
1119 $tag = $tag_eisa if $1 eq 'pnp';
1120 $tag = $tag_usb if $1 eq 'usb';
1121
1122 $spec = $2;
1123
1124 $val = [];
1125
1126 $val->[$he_driver] = [ $flag_string, "m\t$module" ];
1127
1128 $key = [];
1129
1130 if($spec =~ /^v($f)d($f)sv($f)sd($f)bc($f)sc($f)i($f)$/ ) {
1131 $key->[$he_vendor_id] = [ $flag_id, $tag, hex $1 ] if $1 ne '*';
1132 $key->[$he_device_id] = [ $flag_id, $tag, hex $2 ] if $2 ne '*';
1133 $key->[$he_subvendor_id] = [ $flag_id, $tag, hex $3 ] if $3 ne '*';
1134 $key->[$he_subdevice_id] = [ $flag_id, $tag, hex $4 ] if $4 ne '*';
1135 $key->[$he_baseclass_id] = [ $flag_id, $tag_none, hex $5 ] if $5 ne '*';
1136 $key->[$he_subclass_id] = [ $flag_id, $tag_none, hex $6 ] if $6 ne '*';
1137 $key->[$he_progif_id] = [ $flag_id, $tag_none, hex $7 ] if $7 ne '*';
1138
1139 push @hd, [ "$file_name($line)", [ $key ], $val ];
1140 }
1141 elsif($spec =~ /^v($f)p($f)dl($f)dh($f)dc($f)dsc($f)dp($f)ic($f)isc($f)ip($f)$/ ) {
1142
1143 if(
1144 $3 == '*' && $4 == '*' && $5 == '*' &&
1145 $6 == '*' && $7 == '*' && $8 == '*' &&
1146 $9 == '*' && $10 == '*'
1147 ) {
1148 $key->[$he_vendor_id] = [ $flag_id, $tag, hex $1 ] if $1 ne '*';
1149 $key->[$he_device_id] = [ $flag_id, $tag, hex $2 ] if $2 ne '*';
1150
1151 push @hd, [ "$file_name($line)", [ $key ], $val ];
1152 }
1153 }
1154 elsif($spec =~ /^[c|d](\S{3})([0-9a-fA-FX]{4})/ ) {
1155 $t1 = $1;
1156 $t2 = $2;
1157
1158 if($t1 =~ /[\@A-Z\[\\\]\^_]{3}/ && $t2 ne 'XXXX') {
1159 $key->[$he_vendor_id] = [ $flag_id, $tag, eisa_id $t1 ];
1160 $key->[$he_device_id] = [ $flag_id, $tag, hex $t2 ];
1161
1162 push @hd, [ "$file_name($line)", [ $key ], $val ];
1163 }
1164 }
1165 else {
1166 die "invalid line: $file_name($line)\n"
1167 }
1168 }
1169 }
1170
1171
1172 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1173 #
1174 # convert 3-letter eisa id to number
1175 #
1176
1177 sub eisa_id
1178 {
1179 my ( $str, $id, $i, $j );
1180
1181 $str = shift;
1182 $id = 0;
1183
1184 die "internal oops" unless length($str) == 3;
1185 for($i = 0; $i < 3; $i++) {
1186 $id <<= 5;
1187 $j = ord substr $str, $i, 1;
1188 $j -= ord('A') - 1;
1189 die "internal oops" unless $j >= 0 && $j <= 0x1f;
1190 $id += $j;
1191 }
1192
1193 return $id;
1194 }
1195
1196
1197 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1198 #
1199 # convert numerical eisa id to 3-letter string
1200 #
1201
1202 sub eisa_str
1203 {
1204 my ( $id, $str );
1205
1206 $id = shift;
1207
1208 die "internal oops: eisa id \"$id\"" unless $id >= 0 && $id <= 0x7fff;
1209
1210 $str = chr((($id >> 10) & 0x1f) + ord('A') - 1);
1211 $str .= chr((($id >> 5) & 0x1f) + ord('A') - 1);
1212 $str .= chr(( $id & 0x1f) + ord('A') - 1);
1213
1214 return $str;
1215 }
1216
1217
1218 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1219 #
1220 # remove entries that have no effect
1221 #
1222
1223 sub remove_nops
1224 {
1225 my ($hd, $id, $f, $i, $cf);
1226 local $_;
1227
1228 for $hd (@hd) {
1229 if(!defined($hd->[1]) || !@{$hd->[1]} || !defined($hd->[2]) || !@{$hd->[2]}) {
1230 undef $hd;
1231 next;
1232 }
1233 for $id (@{$hd->[1]}, $hd->[2]) {
1234 if(defined($id)) {
1235 $cf = 0;
1236 for $f (@$id) {
1237 if(defined $f) {
1238 $cf++;
1239 if(@$f == 2 && $f->[0] == $flag_string && $f->[1] eq "") {
1240 undef $f;
1241 $cf--;
1242 }
1243 }
1244 }
1245 undef $id if !$cf;
1246 }
1247 }
1248 if(!defined($hd->[1]) || !@{$hd->[1]} || !defined($hd->[2]) || !@{$hd->[2]}) {
1249 print STDERR "$hd->[0] has no info, dropped\n";
1250 undef $hd;
1251 next;
1252 }
1253 }
1254
1255 @hd = grep { defined } @hd;
1256 }
1257
1258
1259 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1260 #
1261 # remove duplicate entries
1262 #
1263
1264 sub remove_duplicates
1265 {
1266 my ($hd, $hd0, $hd1, $len, $i, $j, $m, $v, $buf, $errors, $drop);
1267 local $_;
1268
1269 $len = @hd;
1270
1271 for($j = 0; $j < $len; $j++) {
1272 print STDERR ">> $j\r";
1273 $hd0 = \$hd[$j];
1274 for($i = $j + 1; $i < $len; $i++) {
1275 $hd1 = \$hd[$i];
1276 $m = match_item $$hd0, $$hd1;
1277 # print "$$hd0->[0] -- $$hd1->[0]: $m\n";
1278 if($m) {
1279 $drop = cmp_item $$hd0, $$hd1;
1280 $drop = !$drop || abs($drop) == 2 ? ", dropped" : undef;
1281 undef $buf;
1282 # print STDERR "j: $$hd0->[0], $$hd1->[0]\n";
1283 $v = join_skey $$hd0->[2], $$hd1->[2], \$buf, \$errors;
1284 if($errors) {
1285 print STDERR "$$hd1->[0] conflicts with $$hd0->[0]$drop:\n$buf\n";
1286 $$hd1 = undef if $drop;
1287 }
1288 else {
1289 if($drop) {
1290 print STDERR "$$hd1->[0] added to $$hd0->[0] and dropped\n";
1291 $$hd0->[2] = $v;
1292 # $$hd1 = undef;
1293 }
1294 else {
1295 print STDERR "$$hd1->[0] shadowed by $$hd0->[0]\n";
1296 $$hd0->[2] = $v;
1297 }
1298 }
1299 }
1300 }
1301 }
1302
1303 @hd = grep { defined } @hd;
1304
1305 for $hd (@hd) {
1306 if(
1307 !defined($hd->[2]) ||
1308 !defined($hd->[2][$he_driver]) ||
1309 !(defined($hd->[2][$he_device_name]) || defined($hd->[2][$he_subdevice_name]))
1310 ) {
1311 undef $hd;
1312 next;
1313 }
1314 }
1315
1316 @hd = grep { defined } @hd;
1317
1318 }
1319
1320
1321 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1322 #
1323 # remove duplicate entries
1324 #
1325
1326 sub remove_duplicatesx
1327 {
1328 my ($hd0, $hd1, $len, $i, $j, $m, $v, $buf, $errors, $drop);
1329 local $_;
1330
1331 $len = @hd;
1332
1333 for($j = 0; $j < $len; $j++) {
1334 print STDERR ">> $j\r";
1335 $hd0 = \$hd[$j];
1336 for($i = $j + 1; $i < $len; $i++) {
1337 $hd1 = \$hd[$i];
1338 $m = match_item $$hd0, $$hd1;
1339 # print "$$hd0->[0] -- $$hd1->[0]: $m\n";
1340 if($m) {
1341 $drop = cmp_item $$hd0, $$hd1;
1342 $drop = !$drop || abs($drop) == 2 ? ", dropped" : undef;
1343 undef $buf;
1344 $v = join_skey $$hd0->[2], $$hd1->[2], \$buf, \$errors;
1345 if($errors) {
1346 print STDERR "$$hd1->[0] conflicts with $$hd0->[0]$drop:\n$buf\n";
1347 $$hd1 = undef if $drop;
1348 }
1349 else {
1350 if($drop) {
1351 print STDERR "$$hd1->[0] added to $$hd0->[0] and dropped\n";
1352 $$hd0->[2] = $v;
1353 $$hd1 = undef;
1354 }
1355 else {
1356 print STDERR "$$hd1->[0] shadowed by $$hd0->[0]\n";
1357 }
1358 }
1359 }
1360 }
1361 }
1362
1363 @hd = grep { defined } @hd;
1364 }
1365
1366
1367 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1368 #
1369 # fix drive info
1370 #
1371
1372 sub fix_driver_info
1373 {
1374 my ($hd, $hid, $drv, $i, @i, @info, @req, %req);
1375
1376 for $hd (@hd) {
1377 if(
1378 !defined($hd->[2]) ||
1379 !defined($hd->[2][$he_driver])
1380 ) {
1381 next;
1382 }
1383 $hid = $hd->[2][$he_driver];
1384 next unless $hid->[0] == $flag_string;
1385
1386 undef @req;
1387
1388 for $drv (@$hid[1 .. @$hid - 1]) {
1389 @i = split /\x00/, $drv;
1390 for $i (@i) {
1391 next if $i =~ /^[MX]\t/;
1392 $i =~ s/\|+$//;
1393 next unless $i =~ /^x\t/;
1394 @info = split /\|/, $i;
1395 # remove leasding 'XF86_' from server name
1396 $info[1] =~ s/^XF86_// if $info[1];
1397 # sort package, extension and option lists
1398 push @req, split /,/, $info[3] if $info[3];
1399 # $info[3] = join ',', sort split /,/, $info[3] if $info[3];
1400 $info[3] = undef if $info[3];
1401 $info[4] = join ',', sort split /,/, $info[4] if $info[4];
1402 $info[5] = join ',', sort split /,/, $info[5] if $info[5];
1403 $info[6] = join ',', sort { $a <=> $b } split /,/, $info[6] if $info[6];
1404 $i = join '|', @info;
1405 }
1406 $drv = join "\x00", @i;
1407 # print ">$drv<\n"
1408 }
1409
1410 if(@req) {
1411 $hid = $hd->[2][$he_requires];
1412 if($hid) {
1413 if($hid->[0] != $flag_string) {
1414 die "oops, invalid data"
1415 }
1416 push @req, split /\|/, $hid->[1];
1417 $hid->[1] = join '|', @req;
1418 }
1419 else {
1420 $hd->[2][$he_requires] = [ $flag_string, join('|', @req) ];
1421 }
1422 }
1423 }
1424
1425 for $hd (@hd) {
1426 if(
1427 !defined($hd->[2]) ||
1428 !defined($hd->[2][$he_requires])
1429 ) {
1430 next;
1431 }
1432 $hid = $hd->[2][$he_requires];
1433 next unless $hid->[0] == $flag_string;
1434
1435 undef @req;
1436 undef %req;
1437
1438 @req = split /\|/, $hid->[1];
1439 @req{@req} = @req;
1440
1441 $hid->[1] = join '|', sort keys %req;
1442 }
1443 }
1444
1445
1446 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1447 #
1448 # hd: [ "source", [ skey, skey, ... ], [ val ] ]
1449 # skey/val: [ ... , id, ..., id, ... ]
1450 # id: [ $flag_id, $tag, $value, $range, $mask ]
1451 # id: [ $flag_string, "str", "str", ... ]
1452
1453 sub cmp_id
1454 {
1455 my ($id0, $id1, $len0, $len1, $len, $i, $k);
1456
1457 ($id0, $id1) = @_;
1458
1459 return 0 if !defined($id0) && !defined($id1);
1460 return -1 if !defined($id0);
1461 return 1 if !defined($id1);
1462
1463 if($id0->[0] != $id1->[0]) {
1464 return $id0->[0] <=> $id1->[0];
1465 }
1466
1467 $len0 = @$id0;
1468 $len1 = @$id1;
1469 $len = $len0 < $len1 ? $len0 : $len1;
1470
1471 if($id0->[0] == $flag_string) {
1472 for($i = 1; $i < $len; $i++) {
1473 $k = $id0->[$i] cmp $id1->[$i];
1474 return $k if $k;
1475 }
1476 return $len0 <=> $len1;
1477 }
1478
1479 if($id0->[0] == $flag_id) {
1480 $k = $id0->[1] <=> $id1->[1];
1481 return $k if $k;
1482 $k = $id0->[2] <=> $id1->[2];
1483 return $k if $k;
1484 $k = $len0 <=> $len1;
1485 return $k if $k || $len <= 3;
1486 # print "-\n";
1487 # $dump->dumpValue( $id0 );
1488 # $dump->dumpValue( $id1 );
1489 # die "internal oops: strange id" if $len < 4;
1490 $i = $len - 1;
1491 return -1 if !defined($id0->[$i]);
1492 return 1 if !defined($id1->[$i]);
1493 return $id0->[$i] <=> $id1->[$i];
1494 }
1495
1496 die "internal oops: can't compare that!";
1497 }
1498
1499
1500 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1501 #
1502 sub cmp_skey
1503 {
1504 my ($skey0, $skey1, $len0, $len1, $len, $i, $k);
1505
1506 ($skey0, $skey1) = @_;
1507
1508 return 0 if !defined($skey0) && !defined($skey1);
1509 return -1 if !defined($skey0);
1510 return 1 if !defined($skey1);
1511
1512 $len0 = @$skey0;
1513 $len1 = @$skey1;
1514 $len = $len0 < $len1 ? $len0 : $len1;
1515
1516 # $dump->dumpValue( $skey0 );
1517 # $dump->dumpValue( $skey1 );
1518
1519 for($i = 0; $i < $len; $i++) {
1520 next unless defined($skey0->[$i]) || defined($skey1->[$i]);
1521
1522 # note: this looks reversed, but is intentional!
1523 return 1 if !defined($skey0->[$i]);
1524 return -1 if !defined($skey1->[$i]);
1525
1526 $k = cmp_id $skey0->[$i], $skey1->[$i];
1527
1528 return $k if $k;
1529 }
1530
1531 return $len0 <=> $len1;
1532 }
1533
1534
1535 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1536 #
1537 # 0: equal
1538 # +-1: differing keys
1539 # +-2: differing values
1540 #
1541 sub cmp_item
1542 {
1543 my ($item0, $item1, $len0, $len1, $len, $i, $k);
1544
1545 ($item0, $item1) = @_;
1546
1547 $cmp_item_cnt++;
1548
1549 return 0 if !defined($item0) && !defined($item1);
1550 return -1 if !defined($item0);
1551 return 1 if !defined($item1);
1552
1553 $len0 = @{$item0->[1]};
1554 $len1 = @{$item1->[1]};
1555 $len = $len0 < $len1 ? $len0 : $len1;
1556
1557 # $dump->dumpValue( $item0 );
1558
1559 for($i = 0; $i < $len; $i++) {
1560 return -1 if !defined($item0->[1][$i]);
1561 return 1 if !defined($item1->[1][$i]);
1562 $k = cmp_skey $item0->[1][$i], $item1->[1][$i];
1563 # print " skey: $k\n";
1564 return $k if $k;
1565 }
1566 $k = $len0 <=> $len1;
1567 return $k if $k;
1568
1569 return 0 if !defined($item0->[2]) && !defined($item1->[2]);
1570 return -2 if !defined($item0->[2]);
1571 return 2 if !defined($item1->[2]);
1572
1573 $k = cmp_skey $item0->[2], $item1->[2];
1574 # print " val: $k\n";
1575 return 2 * $k;
1576 }
1577
1578
1579 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1580 #
1581 # check if id1 is part of id0
1582 #
1583 # return:
1584 # 1: yes
1585 # 0: no
1586 # undef: don't know
1587 #
1588 # hd: [ "source", [ skey, skey, ... ], [ val ] ]
1589 # skey/val: [ ... , id, ..., id, ... ]
1590 # id: [ $flag_id, $tag, $value, $range, $mask ]
1591 # id: [ $flag_string, "str", "str", ... ]
1592
1593 sub match_id
1594 {
1595 my ($id0, $id1, $len0, $len1, $len, $i, $k);
1596
1597 ($id0, $id1) = @_;
1598
1599 return 0 if !defined($id0) || !defined($id1);
1600
1601 return 0 if $id0->[0] != $id1->[0];
1602
1603 $len0 = @$id0;
1604 $len1 = @$id1;
1605 $len = $len0 < $len1 ? $len0 : $len1;
1606
1607 if($id0->[0] == $flag_string) {
1608 for($i = 1; $i < $len; $i++) {
1609 return 0 if $id0->[$i] cmp $id1->[$i];
1610 }
1611 return $len0 != $len1 ? 0 : 1;
1612 }
1613
1614 if($id0->[0] == $flag_id) {
1615 return 0 if $id0->[1] != $id1->[1];
1616 if($len1 == 3) {
1617 if($len0 == 3) {
1618 return $id0->[2] != $id1->[2] ? 0 : 1;
1619 }
1620 elsif($len0 == 4) {
1621 return $id1->[2] >= $id0->[2] && $id1->[2] < $id0->[2] + $id0->[3] ? 1 : 0;
1622 }
1623 elsif($len0 == 5) {
1624 return ($id1->[2] & ~$id0->[4]) == $id0->[2] ? 1 : 0;
1625 }
1626 else {
1627 die "invalid id";
1628 }
1629 }
1630 elsif($len1 == 4) {
1631 return undef;
1632 }
1633 elsif($len1 == 5) {
1634 return undef;
1635 }
1636 else {
1637 die "invalid id";
1638 }
1639 }
1640
1641 die "internal oops: can't match that!";
1642 }
1643
1644
1645 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1646 #
1647 # skey1 part of skey0?
1648 #
1649 sub match_skey
1650 {
1651 my ($skey0, $skey1, $len0, $len1, $len, $i, $k);
1652
1653 ($skey0, $skey1) = @_;
1654
1655 return 0 if !defined($skey0) || !defined($skey1);
1656
1657 $len0 = @$skey0;
1658 $len1 = @$skey1;
1659
1660 $len = $len0 > $len1 ? $len0 : $len1;
1661
1662 # $dump->dumpValue( $skey0 );
1663 # $dump->dumpValue( $skey1 );
1664
1665 for($i = 0; $i < $len; $i++) {
1666 next unless defined($skey1->[$i]);
1667
1668 return 0 if !defined($skey0->[$i]) && defined($skey1->[$i]);
1669
1670 $k = match_id $skey0->[$i], $skey1->[$i];
1671
1672 return $k if !$k;
1673 }
1674
1675 return 1;
1676 }
1677
1678
1679 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1680 #
1681 # item1 part of item0?
1682 #
1683 sub match_item
1684 {
1685 my ($item0, $item1, $len0, $len1, $i, $j, $k, $m);
1686
1687 ($item0, $item1) = @_;
1688
1689 $match_item_cnt++;
1690
1691 return 0 if !defined($item0) || !defined($item1);
1692
1693 $len0 = @{$item0->[1]};
1694 $len1 = @{$item1->[1]};
1695
1696 for($j = 0; $j < $len1; $j++) {
1697 for($i = 0; $i < $len0; $i++) {
1698 $k = match_skey $item0->[1][$i], $item1->[1][$j];
1699 $m = $k if defined $k;
1700 return $k if $k;
1701 }
1702 }
1703
1704 return $m
1705 }
1706
1707
1708 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1709 #
1710 # add skey1 to skey0
1711 #
1712 sub join_skey
1713 {
1714 my ($skey0, $skey1, $len, $i, $k, $n, $buf, $err);
1715
1716 ($skey0, $skey1, $buf, $errors) = @_;
1717
1718 $$errors = 0;
1719
1720 return undef if !defined($skey0) && !defined($skey1);
1721 return [ @$skey0 ] if !defined($skey1);
1722 return [ @$skey1 ] if !defined($skey0);
1723
1724 $n = [ @$skey0 ];
1725
1726 $len = @$skey1;
1727
1728 for($i = 0; $i < $len; $i++) {
1729 next unless defined $skey1->[$i];
1730
1731 $n->[$i] = $skey1->[$i];
1732
1733 next unless defined $skey0->[$i];
1734
1735 $k = cmp_id $skey0->[$i], $skey1->[$i];
1736
1737 if($k) {
1738 if(defined $buf) {
1739 if($i != $he_driver) {
1740 $$buf .= ent_name_pr(" 0:", $ent_names[$i]);
1741 $$buf .= id_dump($i, $skey0->[$i]) . "\n";
1742 $$buf .= ent_name_pr(" 1:", $ent_names[$i]);
1743 $$buf .= id_dump($i, $skey1->[$i]) . "\n";
1744 }
1745 else {
1746 $$buf .= drv_dump(" 0:", $skey0->[$i]);
1747 $$buf =~ s/\n&/\n 0:/;
1748 $$buf .= drv_dump(" 1:", $skey1->[$i]);
1749 $$buf =~ s/\n&/\n 1:/;
1750 }
1751 }
1752 $$errors++ if defined $errors;
1753 }
1754 }
1755
1756 return $n;
1757 }
1758
1759
1760
1761 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1762 #
1763 # split key fields
1764 #
1765 sub split_item
1766 {
1767 my ($item, @items, $tmp);
1768 local $_;
1769
1770 $item = shift;
1771
1772 return $item if !defined($item) || !defined($item->[1]);
1773
1774 for (@{$item->[1]}) {
1775 $tmp = [ @$item ];
1776 $tmp->[1] = [ $_ ];
1777 push @items, $tmp;
1778 }
1779
1780 return @items;
1781 }
1782
1783
1784 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1785
1786 sub get_xml_data
1787 {
1788 my ($xml, $i, $j);
1789
1790 $xml = shift;
1791
1792 if($xml->[0] ne 'hwdata') {
1793 die "invalid XML root element (expected 'hwdata')\n"
1794 }
1795
1796 for($i = 1; $i < @{$xml->[1]}; $i += 2) {
1797 if($xml->[1][$i] eq 'item') {
1798 push @hd, parse_xml_item($xml->[1][$i + 1]);
1799 }
1800 }
1801 }
1802
1803
1804 sub parse_xml_item
1805 {
1806 my (@xml, %attr, $i, $item);
1807
1808 @xml = @{$_[0]};
1809 %attr = %{shift @xml};
1810
1811 for($i = 0; $i < @xml; $i += 2) {
1812 if($xml[$i] eq 'key') {
1813 push @{$item->[1]}, parse_xml_key($xml[$i + 1]);
1814 }
1815 else {
1816 $item->[2] = parse_xml_key($_[0]);
1817 }
1818 }
1819
1820 return $item;
1821 }
1822
1823
1824 sub parse_xml_key
1825 {
1826 my (@xml, %attr, $i, @key, $val, $id, $is_id, $keyid, $keyid2, $tmp);
1827
1828 @xml = @{$_[0]};
1829 %attr = %{shift @xml};
1830
1831 for($i = 0; $i < @xml; $i += 2) {
1832 next if $xml[$i] eq '0' || $xml[$i] eq 'key';
1833
1834 $keyid = $xml_values{$xml[$i]};
1835 $is_id = $keyid < $he_nomask && $ent_names[$keyid] =~ /\.(id|name)$/ ? 1 : 0;
1836
1837 if(!defined($keyid)) {
1838 die "invalid key element \"$xml[$i]\"\n";
1839 }
1840
1841 if($keyid == $he_driver) {
1842 $id = parse_xml_driver($xml[$i + 1]);
1843 if(!defined($key[$keyid])) {
1844 $key[$keyid] = $id;
1845 }
1846 else {
1847 push @{$key[$keyid]}, $id->[1];
1848 }
1849 }
1850 elsif($is_id) {
1851 $id = parse_xml_id($xml[$i + 1]);
1852 if($id->[0] == $flag_id) {
1853 $tmp = $ent_names[$keyid];
1854 $tmp =~ s/\.name$/.id/;
1855 $keyid2 = $ent_values{$tmp};
1856 if(!defined($keyid2)) {
1857 die "oops, no .id for $xml[$i]?";
1858 }
1859 }
1860 else {
1861 $tmp = $ent_names[$keyid];
1862 $tmp =~ s/\.id$/.name/;
1863 $keyid2 = $ent_values{$tmp};
1864 if(!defined($keyid2)) {
1865 die "oops, no .name for $xml[$i]?";
1866 }
1867 }
1868 $key[$keyid2] = $id;
1869 }
1870 else {
1871 $val = parse_xml_cdata($xml[$i + 1]);
1872 if(defined($key[$keyid]) && $keyid == $he_requires) {
1873 $key[$keyid][1] .= "|$val";
1874 }
1875 else {
1876 $key[$keyid] = [ $flag_string, $val ];
1877 }
1878 }
1879 }
1880
1881 return [ @key ];
1882 }
1883
1884
1885 sub parse_xml_id
1886 {
1887 my (@xml, %attr, $i, $id, $val);
1888
1889 @xml = @{$_[0]};
1890 %attr = %{shift @xml};
1891
1892 for($i = 0; $i < @xml; $i += 2) {
1893 next if $xml[$i] eq '0';
1894
1895 if($xml[$i] eq 'id') {
1896 $id = parse_xml_id_id($xml[$i + 1]);
1897 }
1898 elsif($xml[$i] eq 'idrange') {
1899 $id = parse_xml_id_range($xml[$i + 1]);
1900 }
1901 elsif($xml[$i] eq 'idmask') {
1902 $id = parse_xml_id_mask($xml[$i + 1]);
1903 }
1904 elsif($xml[$i] eq 'name') {
1905 $val = parse_xml_cdata($xml[$i + 1]);
1906 $id = [ $flag_string, $val ];
1907 }
1908 else {
1909 die "invalid id element \"$xml[$i]\"\n";
1910 }
1911 }
1912
1913 return $id;
1914 }
1915
1916
1917 sub parse_xml_id_id
1918 {
1919 my (@xml, %attr, $i, $tag, $value);
1920
1921 @xml = @{$_[0]};
1922 %attr = %{shift @xml};
1923
1924 $tag = $tag_values{$attr{type}};
1925
1926 if(!defined($tag)) {
1927 die "missing/unsupported id attribute \"$attr{type}\"\n";
1928 }
1929
1930 for($i = 0; $i < @xml; $i += 2) {
1931 if($xml[$i] eq '0') {
1932 $value = idstr2value $tag, $xml[$i + 1];
1933 }
1934 else {
1935 die "cdata expected, got \"$xml[$i]\"\n";
1936 }
1937 }
1938
1939 return [ $flag_id, $tag, $value ];
1940 }
1941
1942
1943 sub parse_xml_id_range
1944 {
1945 my (@xml, %attr, $i, $tag, $value, $range);
1946
1947 @xml = @{$_[0]};
1948 %attr = %{shift @xml};
1949
1950 $tag = $tag_values{$attr{type}};
1951
1952 if(!defined($tag)) {
1953 die "missing/unsupported id attribute \"$attr{type}\"\n";
1954 }
1955
1956 for($i = 0; $i < @xml; $i += 2) {
1957 next if $xml[$i] eq '0';
1958 if($xml[$i] eq 'first') {
1959 $value = idstr2value $tag, parse_xml_cdata($xml[$i + 1]);
1960 }
1961 elsif($xml[$i] eq 'last') {
1962 $range = idstr2value $tag, parse_xml_cdata($xml[$i + 1]);
1963 }
1964 else {
1965 die "invalid idrange element \"$xml[$i]\"\n";
1966 }
1967 }
1968
1969 if(!defined($value) || !defined($range)) {
1970 die "invalid idrange\n";
1971 }
1972
1973 return [ $flag_id, $tag, $value, $range - $value + 1 ];
1974 }
1975
1976
1977 sub parse_xml_id_mask
1978 {
1979 my (@xml, %attr, $i, $tag, $value, $mask);
1980
1981 @xml = @{$_[0]};
1982 %attr = %{shift @xml};
1983
1984 $tag = $tag_values{$attr{type}};
1985
1986 if(!defined($tag)) {
1987 die "missing/unsupported id attribute \"$attr{type}\"\n";
1988 }
1989
1990 for($i = 0; $i < @xml; $i += 2) {
1991 next if $xml[$i] eq '0';
1992 if($xml[$i] eq 'value') {
1993 $value = idstr2value $tag, parse_xml_cdata($xml[$i + 1]);
1994 }
1995 elsif($xml[$i] eq 'mask') {
1996 $mask = idstr2value $tag, parse_xml_cdata($xml[$i + 1]);
1997 }
1998 else {
1999 die "invalid idmask element \"$xml[$i]\"\n";
2000 }
2001 }
2002
2003 if(!defined($value) || !defined($mask)) {
2004 die "invalid idmask\n";
2005 }
2006
2007 return [ $flag_id, $tag, $value, undef, $mask ];
2008 }
2009
2010
2011 sub parse_xml_driver
2012 {
2013 my (@xml, %attr, $i, $val);
2014
2015 @xml = @{$_[0]};
2016 %attr = %{shift @xml};
2017
2018 for($i = 0; $i < @xml; $i += 2) {
2019 next if $xml[$i] eq '0';
2020
2021 if($xml[$i] eq 'any') {
2022 $val = "a\t" . parse_xml_cdata($xml[$i + 1]);
2023 }
2024 elsif($xml[$i] eq 'display') {
2025 $val = parse_xml_driver_display($xml[$i + 1]);
2026 }
2027 elsif($xml[$i] eq 'module') {
2028 $val = parse_xml_driver_module($xml[$i + 1]);
2029 }
2030 elsif($xml[$i] eq 'mouse') {
2031 $val = parse_xml_driver_mouse($xml[$i + 1]);
2032 }
2033 elsif($xml[$i] eq 'xfree') {
2034 $val = parse_xml_driver_xfree($xml[$i + 1]);
2035 }
2036 else {
2037 die "invalid driver element \"$xml[$i]\"\n";
2038 }
2039 }
2040
2041 return [ $flag_string, $val ];
2042 }
2043
2044
2045 sub parse_xml_driver_display
2046 {
2047 my (@xml, %attr, $i, @val);
2048
2049 @xml = @{$_[0]};
2050 %attr = %{shift @xml};
2051
2052 for($i = 0; $i < @xml; $i += 2) {
2053 next if $xml[$i] eq '0';
2054
2055 if($xml[$i] eq 'resolution') {
2056 $val[0] = join('x', parse_xml_pair($xml[$i + 1], 'width', 'height'));
2057 }
2058 elsif($xml[$i] eq 'vsync') {
2059 $val[1] = join('-', parse_xml_pair($xml[$i + 1], 'min', 'max'));
2060 }
2061 elsif($xml[$i] eq 'hsync') {
2062 $val[2] = join('-', parse_xml_pair($xml[$i + 1], 'min', 'max'));
2063 }
2064 elsif($xml[$i] eq 'bandwidth') {
2065 $val[3] = parse_xml_cdata($xml[$i + 1]);
2066 }
2067 else {
2068 die "invalid display element \"$xml[$i]\"\n";
2069 }
2070 }
2071
2072 if(!@val) {
2073 die "invalid display info\n";
2074 }
2075
2076 return "d\t" . join('|', @val);
2077 }
2078
2079
2080 sub parse_xml_driver_module
2081 {
2082 my (@xml, %attr, $i, $val, $type, @conf, @mods);
2083
2084 @xml = @{$_[0]};
2085 %attr = %{shift @xml};
2086
2087 for($i = 0; $i < @xml; $i += 2) {
2088 next if $xml[$i] eq '0';
2089
2090 $val = parse_xml_cdata($xml[$i + 1]);
2091
2092 if($xml[$i] eq 'modprobe') {
2093 if($type && $type ne 'm') {
2094 die "invalid module info: \"$xml[$i]\"\n";
2095 }
2096 $type = 'm';
2097 push @mods, $val;
2098 }
2099 elsif($xml[$i] eq 'insmod') {
2100 if($type && $type ne 'i') {
2101 die "invalid module info: \"$xml[$i]\"\n";
2102 }
2103 $type = 'i';
2104 push @mods, $val;
2105 }
2106 elsif($xml[$i] eq 'modconf') {
2107 if($type && $type ne 'm') {
2108 die "invalid module info: \"$xml[$i]\"\n";
2109 }
2110 push @conf, "\x00M\t$val";
2111 }
2112 else {
2113 die "invalid module element \"$xml[$i]\"\n";
2114 }
2115 }
2116
2117 if(!$type && !@mods) {
2118 die "invalid module info\n";
2119 }
2120
2121 $val = "$type\t" . join('|', @mods);
2122
2123 if(@conf) {
2124 $val .= join('', @conf);
2125 }
2126
2127 return $val;
2128 }
2129
2130
2131 sub parse_xml_driver_mouse
2132 {
2133 my (@xml, %attr, $i, $val, @val);
2134
2135 @xml = @{$_[0]};
2136 %attr = %{shift @xml};
2137
2138 for($i = 0; $i < @xml; $i += 2) {
2139 next if $xml[$i] eq '0';
2140
2141 $val = parse_xml_cdata($xml[$i + 1]);
2142
2143 if($xml[$i] eq 'xf86') {
2144 $val[0] = $val;
2145 }
2146 elsif($xml[$i] eq 'gpm') {
2147 $val[1] = $val;
2148 }
2149 elsif($xml[$i] eq 'buttons') {
2150 $val[2] = $val;
2151 }
2152 elsif($xml[$i] eq 'wheels') {
2153 $val[3] = $val;
2154 }
2155 else {
2156 die "invalid mouse element \"$xml[$i]\"\n";
2157 }
2158 }
2159
2160 if(!@val) {
2161 die "invalid mouse info\n";
2162 }
2163
2164 return "p\t" . join('|', @val);
2165 }
2166
2167
2168 sub parse_xml_driver_xfree
2169 {
2170 my (@xml, %attr, $i, $val, @val, @conf);
2171
2172 @xml = @{$_[0]};
2173 %attr = %{shift @xml};
2174
2175 for($i = 0; $i < @xml; $i += 2) {
2176 next if $xml[$i] eq '0';
2177
2178 if($xml[$i] eq 'has3d') {
2179 $val[2] = '3d';
2180 }
2181 else {
2182 $val = parse_xml_cdata($xml[$i + 1]);
2183
2184 if($xml[$i] eq 'version') {
2185 $val[0] = $val;
2186 }
2187 elsif($xml[$i] eq 'server') {
2188 $val[1] = $val;
2189 }
2190 elsif($xml[$i] eq 'extension') {
2191 $val[4] .= "," if defined $val[4];
2192 $val[4] .= $val;
2193 }
2194 elsif($xml[$i] eq 'option') {
2195 $val[5] .= "," if defined $val[5];
2196 $val[5] .= $val;
2197 }
2198 elsif($xml[$i] eq 'bpp') {
2199 $val[6] .= "," if defined $val[6];
2200 $val[6] .= $val;
2201 }
2202 elsif($xml[$i] eq 'dacspeed') {
2203 $val[7] = $val;
2204 }
2205 elsif($xml[$i] eq 'script') {
2206 $val[8] = $val;
2207 }
2208 elsif($xml[$i] eq 'xf86conf') {
2209 push @conf, "\x00X\t$val";
2210 }
2211 else {
2212 die "invalid xfree element \"$xml[$i]\"\n";
2213 }
2214 }
2215 }
2216
2217 if(!@val) {
2218 die "invalid xfree info\n";
2219 }
2220
2221 $val = "x\t" . join('|', @val);
2222
2223 if(@conf) {
2224 $val .= join('', @conf);
2225 }
2226
2227 return $val;
2228 }
2229
2230
2231 sub parse_xml_pair
2232 {
2233 my (@xml, %attr, $i, $val0, $val1, $elem0, $elem1);
2234
2235 $elem0 = $_[1];
2236 $elem1 = $_[2];
2237
2238 @xml = @{$_[0]};
2239 %attr = %{shift @xml};
2240
2241 for($i = 0; $i < @xml; $i += 2) {
2242 next if $xml[$i] eq '0';
2243 if($xml[$i] eq $elem0) {
2244 $val0 = parse_xml_cdata($xml[$i + 1]);
2245 }
2246 elsif($xml[$i] eq $elem1) {
2247 $val1 = parse_xml_cdata($xml[$i + 1]);
2248 }
2249 else {
2250 die "invalid element \"$xml[$i]\"\n";
2251 }
2252 }
2253
2254 if(!defined($val0) || !defined($val1)) {
2255 die "invalid element\n";
2256 }
2257
2258 return ($val0, $val1);
2259 }
2260
2261
2262 sub parse_xml_cdata
2263 {
2264 my (@xml, %attr, $i);
2265
2266 @xml = @{$_[0]};
2267 %attr = %{shift @xml};
2268
2269 for($i = 0; $i < @xml; $i += 2) {
2270 if($xml[$i] eq '0') {
2271 return $xml[$i + 1]
2272 }
2273 }
2274 }
2275
2276
2277 sub idstr2value
2278 {
2279 my ($tag, $value);
2280
2281 ($tag, $value) = @_;
2282
2283 if($tag == $tag_eisa && length($value) == 3 && $value !~ /^[0-9]/) {
2284 $value = eisa_id $value;
2285 }
2286 else {
2287 $value = num $value;
2288 }
2289
2290 return $value;
2291 }
2292
2293 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2294
2295 sub ent_name_pr
2296 {
2297 my ($str, $len);
2298
2299 $str = $_[0] . $_[1];
2300
2301 $len = length $str;
2302
2303 $str .= "\t";
2304 $len = ($len & ~7) + 8;
2305 $str .= "\t" x ((24 - $len)/8) if $len < 24;
2306
2307 return $str;
2308 }
2309
2310
2311 sub id_dump
2312 {
2313 my ($id, $ent, $str, $tag, $format);
2314
2315 ($ent, $id) = @_;
2316
2317 if($id->[0] == $flag_id) {
2318 $tag = $id->[1];
2319 if($tag == $tag_eisa && ($ent == $he_vendor_id || $ent == $he_subvendor_id)) {
2320 $str = eisa_str $id->[2];
2321 }
2322 else {
2323 $str .= $tag_name[$tag];
2324 $str .= " " if $tag;
2325 $format = "0x%04x";
2326 $format = "0x%02x" if $ent == $he_bus_id || $ent == $he_subclass_id || $ent == $he_progif_id;
2327 $format = "0x%03x" if $ent == $he_baseclass_id;
2328 $str .= sprintf $format, $id->[2];
2329 }
2330 if(defined $id->[3]) {
2331 $str .= sprintf "+0x%04x", $id->[3];
2332 }
2333 elsif(defined $id->[4]) {
2334 $str .= sprintf "&0x%04x", $id->[4];
2335 }
2336 }
2337 elsif($id->[0] == $flag_string) {
2338 if(defined($id->[2])) {
2339 die "oops: strage string data\n";
2340 }
2341 $str = $id->[1];
2342 }
2343 else {
2344 die "oops: unknown id flag\n"
2345 }
2346
2347 return $str;
2348 }
2349
2350
2351 sub drv_dump
2352 {
2353 my ($id, $str, $i, $pre, $type, $drv, $buf);
2354
2355 ($pre, $id) = @_;
2356
2357 die "oops: invalid driver data\n" if $id->[0] != $flag_string;
2358
2359 for($i = 1; $i < @{$id}; $i++) {
2360 for $drv (split /\x00/, $id->[$i]) {
2361 $type = substr $drv, 0, 2;
2362
2363 if($type eq "x\t") {
2364 $buf .= ent_name_pr($pre, $ent_names[$he_driver_xfree]);
2365 $buf .= substr($drv, 2) . "\n";
2366 }
2367 elsif($type eq "X\t") {
2368 $buf .= ent_name_pr($pre, $ent_names[$he_driver_xfree_config]);
2369 $buf .= substr($drv, 2) . "\n";
2370 }
2371 elsif($type eq "i\t") {
2372 $buf .= ent_name_pr($pre, $ent_names[$he_driver_module_insmod]);
2373 $buf .= substr($drv, 2) . "\n";
2374 }
2375 elsif($type eq "m\t") {
2376 $buf .= ent_name_pr($pre, $ent_names[$he_driver_module_modprobe]);
2377 $buf .= substr($drv, 2) . "\n";
2378 }
2379 elsif($type eq "M\t") {
2380 $buf .= ent_name_pr($pre, $ent_names[$he_driver_module_config]);
2381 $buf .= substr($drv, 2) . "\n";
2382 }
2383 elsif($type eq "p\t") {
2384 $buf .= ent_name_pr($pre, $ent_names[$he_driver_mouse]);
2385 $buf .= substr($drv, 2) . "\n";
2386 }
2387 elsif($type eq "d\t") {
2388 $buf .= ent_name_pr($pre, $ent_names[$he_driver_display]);
2389 $buf .= substr($drv, 2) . "\n";
2390 }
2391 elsif($type eq "a\t") {
2392 $buf .= ent_name_pr($pre, $ent_names[$he_driver_any]);
2393 $buf .= substr($drv, 2) . "\n";
2394 }
2395 else {
2396 die "oops: unhandled driver info type: $drv\n";
2397 }
2398
2399 $pre = "&" if $pre ne "+";
2400 }
2401 }
2402
2403 return $buf;
2404 }
2405
2406
2407 sub ent_dump
2408 {
2409 my ($pre, $id, $ent, $buf);
2410
2411 ($buf, $pre, $id) = @_;
2412
2413 $pre = defined($pre) ? "|" : " " if $pre ne "+";
2414 for($ent = 0; $ent < @{$id}; $ent++) {
2415 if(defined $id->[$ent]) {
2416 if($ent != $he_driver) {
2417 $$buf .= ent_name_pr($pre, $ent_names[$ent]);
2418 $$buf .= id_dump($ent, $id->[$ent]);
2419 $$buf .= "\n";
2420 }
2421 else {
2422 $$buf .= drv_dump($pre, $id->[$ent]);
2423 }
2424 $pre = "&" if $pre ne "+";
2425 }
2426 }
2427
2428 return $pre;
2429 }
2430
2431
2432 sub dump2ids
2433 {
2434 my ($item, $id, $ent, $pre, $buf);
2435
2436 # $dump->dumpValue( \@hd );
2437
2438 open F, ">hd.ids";
2439
2440 for $item (@hd) {
2441 undef $buf;
2442 undef $pre;
2443 print F "# $item->[0]\n" if $opt_with_source;
2444 for $id (@{$item->[1]}) {
2445 $pre = ent_dump \$buf, $pre, $id;
2446 }
2447 $pre = "+";
2448 ent_dump \$buf, $pre, $item->[2];
2449 $buf .= "\n";
2450
2451 print F $buf;
2452 }
2453
2454 close F;
2455 }
2456
2457
2458 # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2459
2460 sub dump2xml
2461 {
2462 my ($item, $dtd);
2463
2464 if($opt_internal_dtd) {
2465 $dtd = hd_dtd_internal;
2466 }
2467 else {
2468 $dtd = "<!DOCTYPE hwdata SYSTEM \"hd.dtd\">\n";
2469 }
2470
2471 $xml_file = new IO::File(">hd.xml");
2472 $xml = new XML::Writer(OUTPUT => $xml_file, DATA_MODE => 1, DATA_INDENT => 2);
2473
2474 $xml->xmlDecl("utf-8");
2475
2476 print $xml_file "\n$dtd";
2477
2478 $xml->startTag("hwdata");
2479
2480 print $xml_file "\n";
2481
2482 for $item (@hd) {
2483 dump_xml_item $item;
2484 }
2485
2486 $xml->endTag("hwdata");
2487 $xml->end();
2488
2489 if(!$opt_internal_dtd) {
2490 print STDERR "writing \"hd.dtd\"\n";
2491 open DTD, ">hd.dtd";
2492 print DTD hd_dtd;
2493 close DTD;
2494 }
2495 }
2496
2497
2498 sub dump_xml_id
2499 {
2500 my ($ent, $id, $i, $tag, $str, $format, $range, $mask);
2501
2502 ($ent, $id) = @_;
2503
2504 $i = $xml_names[$ent];
2505
2506 die "oops: entry $ent not allowed here\n" unless $i;
2507
2508 if($ent == $he_requires) {
2509 if($id->[0] == $flag_string) {
2510 die "oops: strange string data\n" if defined $id->[2];
2511 for $str (split /\|/, $id->[1]) {
2512 $xml->dataElement("requires", $str);
2513 }
2514 }
2515 else {
2516 die "oops: requires _id_???\n"
2517 }
2518 }
2519 else {
2520 $xml->startTag($i);
2521
2522 if($ent == $he_serial) {
2523 if($id->[0] == $flag_string) {
2524 die "oops: strange string data\n" if defined $id->[2];
2525 $xml->characters($id->[1]);
2526 }
2527 else {
2528 die "oops: serial _id_???\n"
2529 }
2530 }
2531 else {
2532 if($id->[0] == $flag_id) {
2533 $tag = $id->[1];
2534 if($tag == $tag_eisa && ($ent == $he_vendor_id || $ent == $he_subvendor_id)) {
2535 $str = eisa_str $id->[2];
2536 }
2537 else {
2538 $format = "0x%04x";
2539 $format = "0x%02x" if $ent == $he_bus_id || $ent == $he_subclass_id || $ent == $he_progif_id;
2540 $format = "0x%03x" if $ent == $he_baseclass_id;
2541 $str = sprintf $format, $id->[2];
2542 }
2543 if(defined $id->[3]) {
2544 if($tag == $tag_eisa && ($ent == $he_vendor_id || $ent == $he_subvendor_id)) {
2545 $range = eisa_str $id->[2] + $id->[3] - 1;
2546 }
2547 else {
2548 $range = sprintf "0x%04x", $id->[2] + $id->[3] - 1;
2549 }
2550 }
2551 elsif(defined $id->[4]) {
2552 $mask = sprintf "0x%04x", $id->[4];
2553 }
2554 $tag = $tag_name[$tag];
2555
2556 if(defined $range) {
2557 if($tag) {
2558 $xml->startTag("idrange", "type" => $tag);
2559 }
2560 else {
2561 $xml->startTag("idrange");
2562 }
2563 $xml->dataElement("first", $str);
2564 $xml->dataElement("last", $range);
2565 $xml->endTag();
2566 }
2567 elsif(defined $mask) {
2568 if($tag) {
2569 $xml->startTag("idmask", "type" => $tag);
2570 }
2571 else {
2572 $xml->startTag("idmask");
2573 }
2574 $xml->dataElement("value", $str);
2575 $xml->dataElement("mask", $mask);
2576 $xml->endTag();
2577 }
2578 else {
2579 if($tag) {
2580 $xml->dataElement("id", $str, "type" => $tag);
2581 }
2582 else {
2583 $xml->dataElement("id", $str);
2584 }
2585 }
2586 }
2587 elsif($id->[0] == $flag_string) {
2588 die "oops: strage string data\n" if defined $id->[2];
2589 $xml->dataElement("name", $id->[1]);
2590 }
2591 else {
2592 die "oops: unknown id flag\n"
2593 }
2594 }
2595
2596 $xml->endTag();
2597 }
2598 }
2599
2600
2601 sub dump_xml_drv
2602 {
2603 my ($id, $str, $i, $j, $k, $type, $drv, $info, @info, $current);
2604
2605 $id = shift;
2606
2607 die "oops: invalid driver data\n" if $id->[0] != $flag_string;
2608
2609 for($i = 1; $i < @{$id}; $i++) {
2610
2611 $xml->startTag('driver');
2612
2613 undef $current;
2614
2615 for $drv (split /\x00/, $id->[$i]) {
2616 $type = substr $drv, 0, 2;
2617 $info = substr $drv, 2;
2618 @info = split /\|/, $info;
2619
2620 if($type eq "i\t") {
2621 $xml->endTag() if $current; $current = $type;
2622 $xml->startTag('module');
2623 for $j (@info) {
2624 $xml->dataElement('insmod', $j);
2625 }
2626 }
2627 elsif($type eq "m\t") {
2628 $xml->endTag() if $current; $current = $type;
2629 $xml->startTag('module');
2630 for $j (@info) {
2631 $xml->dataElement('modprobe', $j);
2632 }
2633 }
2634 elsif($type eq "M\t") {
2635 die "oops: incorrect driver info: $drv\n" unless $current eq "m\t";
2636 $xml->dataElement('modconf', $info);
2637 }
2638 elsif($type eq "a\t") {
2639 $xml->endTag() if $current; $current = undef;;
2640 $xml->dataElement('any', $info);
2641 }
2642 elsif($type eq "d\t") {
2643 $xml->endTag() if $current; $current = undef;
2644 $xml->startTag('display');
2645 if($info[0] =~ /^(\d+)x(\d+)$/) {
2646 ($j, $k) = ($1, $2);
2647 $xml->startTag('resolution');
2648 $xml->dataElement('width', $j);
2649 $xml->dataElement('height', $k);
2650 $xml->endTag('resolution');
2651 }
2652 if($info[1] =~ /^(\d+)-(\d+)$/) {
2653 ($j, $k) = ($1, $2);
2654 $xml->startTag('vsync');
2655 $xml->dataElement('min', $j);
2656 $xml->dataElement('max', $k);
2657 $xml->endTag('vsync');
2658 }
2659 if($info[2] =~ /^(\d+)-(\d+)$/) {
2660 ($j, $k) = ($1, $2);
2661 $xml->startTag('hsync');
2662 $xml->dataElement('min', $j);
2663 $xml->dataElement('max', $k);
2664 $xml->endTag('hsync');
2665 }
2666 if($info[3] =~ /^\d+$/) {
2667 $xml->dataElement('bandwidth', $info[3]);
2668 }
2669 $xml->endTag('display');
2670 }
2671 elsif($type eq "x\t") {
2672 $xml->endTag() if $current; $current = $type;
2673 $xml->startTag('xfree');
2674 if(defined $info[0]) {
2675 $xml->dataElement('version', $info[0]);
2676 }
2677 if($info[1]) {
2678 $xml->dataElement('server', $info[1]);
2679 }
2680 if($info[2]) {
2681 $xml->emptyTag('has3d');
2682 }
2683 # if($info[3]) {
2684 # for $j (split /,/, $info[3]) {
2685 # $xml->dataElement('package', $j);
2686 # }
2687 # }
2688 if($info[4]) {
2689 for $j (split /,/, $info[4]) {
2690 $xml->dataElement('extension', $j);
2691 }
2692 }
2693 if($info[5]) {
2694 for $j (split /,/, $info[5]) {
2695 $xml->dataElement('option', $j);
2696 }
2697 }
2698 if($info[6]) {
2699 for $j (split /,/, $info[6]) {
2700 $xml->dataElement('bpp', $j);
2701 }
2702 }
2703 if($info[7] =~ /^\d+$/) {
2704 $xml->dataElement('dacspeed', $info[7]);
2705 }
2706 if($info[8]) {
2707 $xml->dataElement('script', $info[8]);
2708 }
2709 }
2710 elsif($type eq "X\t") {
2711 die "oops: incorrect driver info: $drv\n" unless $current eq "x\t";
2712 $xml->dataElement('xf86conf', $info);
2713 }
2714 elsif($type eq "p\t") {
2715 $xml->endTag() if $current; $current = undef;
2716 $xml->startTag('mouse');
2717 if($info[0]) {
2718 $xml->dataElement('xf86', $info[0]);
2719 }
2720 if($info[1]) {
2721 $xml->dataElement('gpm', $info[1]);
2722 }
2723 if($info[2] ne "") {
2724 $xml->dataElement('buttons', $info[2]);
2725 }
2726 if($info[3] ne "") {
2727 $xml->dataElement('wheels', $info[3]);
2728 }
2729 $xml->endTag('mouse');
2730 }
2731 else {
2732 $xml->endTag() if $current; $current = undef;
2733 # die "oops: unhandled driver info type: $drv\n";
2734 }
2735 }
2736
2737 $xml->endTag() if $current;
2738
2739 $xml->endTag('driver');
2740
2741 }
2742 }
2743
2744
2745 sub dump_xml_ent
2746 {
2747 my ($id, $ent);
2748
2749 $id = shift;
2750
2751 for($ent = 0; $ent < @{$id}; $ent++) {
2752 if(defined $id->[$ent]) {
2753 if($ent != $he_driver) {
2754 dump_xml_id $ent, $id->[$ent];
2755 }
2756 else {
2757 dump_xml_drv $id->[$ent];
2758 }
2759 }
2760 }
2761
2762 }
2763
2764
2765 sub dump_xml_item
2766 {
2767 my ($item, $id);
2768
2769 $item = shift;
2770
2771 $xml->startTag('item');
2772
2773 for $id (@{$item->[1]}) {
2774 $xml->startTag('key');
2775 dump_xml_ent $id;
2776 $xml->endTag('key');
2777 }
2778
2779 dump_xml_ent $item->[2];
2780
2781 $xml->endTag('item');
2782 print $xml_file "\n";
2783 }
2784
2785
2786 sub hd_dtd
2787 {
2788 my $dtd = <<'EOF'
2789 <!-- libhd DTD V0.2 -->
2790
2791 <!ENTITY % keyfields "bus|baseclass|subclass|progif|vendor|device|subvendor|subdevice|revision|serial|driver|requires">
2792 <!ENTITY % idelements "id|idrange|idmask|name">
2793 <!ENTITY % idtypes "none|pci|eisa|usb|pcmcia|special">
2794
2795 <!ELEMENT hwdata (item*)>
2796
2797 <!ELEMENT item (key+,(%keyfields;)*)>
2798
2799 <!ELEMENT key (%keyfields;)+>
2800
2801 <!ELEMENT bus (%idelements;)>
2802 <!ELEMENT baseclass (%idelements;)>
2803 <!ELEMENT subclass (%idelements;)>
2804 <!ELEMENT progif (%idelements;)>
2805 <!ELEMENT vendor (%idelements;)>
2806 <!ELEMENT device (%idelements;)>
2807 <!ELEMENT subvendor (%idelements;)>
2808 <!ELEMENT subdevice (%idelements;)>
2809 <!ELEMENT revision (%idelements;)>
2810 <!ELEMENT serial (#PCDATA)>
2811 <!ELEMENT requires (#PCDATA)>
2812 <!ELEMENT id (#PCDATA)>
2813 <!ELEMENT idrange (first,last)>
2814 <!ELEMENT first (#PCDATA)>
2815 <!ELEMENT last (#PCDATA)>
2816 <!ELEMENT idmask (value,mask)>
2817 <!ELEMENT value (#PCDATA)>
2818 <!ELEMENT mask (#PCDATA)>
2819 <!ATTLIST id type (%idtypes;) "none">
2820 <!ATTLIST idrange type (%idtypes;) "none">
2821 <!ATTLIST idmask type (%idtypes;) "none">
2822 <!ELEMENT name (#PCDATA)>
2823
2824 <!ELEMENT driver (any|display|module|mouse|xfree)?>
2825
2826 <!ELEMENT any (#PCDATA)>
2827
2828 <!ELEMENT display (resolution?,vsync?,hsync?,bandwidth?)>
2829 <!ELEMENT resolution (width,height)>
2830 <!ELEMENT width (#PCDATA)>
2831 <!ELEMENT height (#PCDATA)>
2832 <!ELEMENT vsync (min,max)>
2833 <!ELEMENT hsync (min,max)>
2834 <!ELEMENT min (#PCDATA)>
2835 <!ELEMENT max (#PCDATA)>
2836 <!ELEMENT bandwidth (#PCDATA)>
2837
2838 <!ELEMENT module (insmod+|(modprobe+,modconf*))>
2839 <!ELEMENT insmod (#PCDATA)>
2840 <!ELEMENT modprobe (#PCDATA)>
2841 <!ELEMENT modconf (#PCDATA)>
2842
2843 <!ELEMENT mouse (xf86?,gpm?,buttons?,wheels?)>
2844 <!ELEMENT xf86 (#PCDATA)>
2845 <!ELEMENT gpm (#PCDATA)>
2846 <!ELEMENT buttons (#PCDATA)>
2847 <!ELEMENT wheels (#PCDATA)>
2848
2849 <!ELEMENT xfree (version,server?,has3d?,extension*,option*,bpp*,dacspeed?,script?,xf86conf*)>
2850 <!ELEMENT version (#PCDATA)>
2851 <!ELEMENT server (#PCDATA)>
2852 <!ELEMENT has3d EMPTY>
2853 <!ELEMENT extension (#PCDATA)>
2854 <!ELEMENT option (#PCDATA)>
2855 <!ELEMENT bpp (#PCDATA)>
2856 <!ELEMENT dacspeed (#PCDATA)>
2857 <!ELEMENT script (#PCDATA)>
2858 <!ELEMENT xf86conf (#PCDATA)>
2859 EOF
2860 ;
2861
2862 return $dtd;
2863 }
2864
2865
2866 sub hd_dtd_internal
2867 {
2868 my $dtd = <<'EOF'
2869 <!DOCTYPE hwdata [
2870 <!ELEMENT hwdata (item*)>
2871 <!ELEMENT item (key+,(bus|baseclass|subclass|progif|vendor|device|subvendor|subdevice|revision|serial|driver|requires)*)>
2872 <!ELEMENT key (bus|baseclass|subclass|progif|vendor|device|subvendor|subdevice|revision|serial|driver|requires)+>
2873 <!ELEMENT bus (id|idrange|idmask|name)>
2874 <!ELEMENT baseclass (id|idrange|idmask|name)>
2875 <!ELEMENT subclass (id|idrange|idmask|name)>
2876 <!ELEMENT progif (id|idrange|idmask|name)>
2877 <!ELEMENT vendor (id|idrange|idmask|name)>
2878 <!ELEMENT device (id|idrange|idmask|name)>
2879 <!ELEMENT subvendor (id|idrange|idmask|name)>
2880 <!ELEMENT subdevice (id|idrange|idmask|name)>
2881 <!ELEMENT revision (id|idrange|idmask|name)>
2882 <!ELEMENT serial (#PCDATA)>
2883 <!ELEMENT requires (#PCDATA)>
2884 <!ELEMENT id (#PCDATA)>
2885 <!ELEMENT idrange (first,last)>
2886 <!ELEMENT first (#PCDATA)>
2887 <!ELEMENT last (#PCDATA)>
2888 <!ELEMENT idmask (value,mask)>
2889 <!ELEMENT value (#PCDATA)>
2890 <!ELEMENT mask (#PCDATA)>
2891 <!ATTLIST id type (none|pci|eisa|usb|pcmcia|special) "none">
2892 <!ATTLIST idrange type (none|pci|eisa|usb|special) "none">
2893 <!ATTLIST idmask type (none|pci|eisa|usb|special) "none">
2894 <!ELEMENT name (#PCDATA)>
2895 <!ELEMENT driver (any|display|module|mouse|xfree)?>
2896 <!ELEMENT any (#PCDATA)>
2897 <!ELEMENT display (resolution?,vsync?,hsync?,bandwidth?)>
2898 <!ELEMENT resolution (width,height)>
2899 <!ELEMENT width (#PCDATA)>
2900 <!ELEMENT height (#PCDATA)>
2901 <!ELEMENT vsync (min,max)>
2902 <!ELEMENT hsync (min,max)>
2903 <!ELEMENT min (#PCDATA)>
2904 <!ELEMENT max (#PCDATA)>
2905 <!ELEMENT bandwidth (#PCDATA)>
2906 <!ELEMENT module (insmod+|(modprobe+,modconf*))>
2907 <!ELEMENT insmod (#PCDATA)>
2908 <!ELEMENT modprobe (#PCDATA)>
2909 <!ELEMENT modconf (#PCDATA)>
2910 <!ELEMENT mouse (xf86?,gpm?,buttons?,wheels?)>
2911 <!ELEMENT xf86 (#PCDATA)>
2912 <!ELEMENT gpm (#PCDATA)>
2913 <!ELEMENT buttons (#PCDATA)>
2914 <!ELEMENT wheels (#PCDATA)>
2915 <!ELEMENT xfree (version,server?,has3d?,extension*,option*,bpp*,dacspeed?,script?,xf86conf*)>
2916 <!ELEMENT version (#PCDATA)>
2917 <!ELEMENT server (#PCDATA)>
2918 <!ELEMENT has3d EMPTY>
2919 <!ELEMENT extension (#PCDATA)>
2920 <!ELEMENT option (#PCDATA)>
2921 <!ELEMENT bpp (#PCDATA)>
2922 <!ELEMENT dacspeed (#PCDATA)>
2923 <!ELEMENT script (#PCDATA)>
2924 <!ELEMENT xf86conf (#PCDATA)>
2925 ]>
2926 EOF
2927 ;
2928
2929 return $dtd;
2930 }
2931