wok view tazndis/stuff/tazndis @ rev 1850

Add: tazndis, replacement for ndiswrapper util.
author Eric Joseph-Alexandre <erjo@slitaz.org>
date Sun Dec 14 10:53:02 2008 +0100 (2008-12-14)
parents
children a2b99f1ee6f4
line source
1 #!/usr/bin/perl
3 #/*
4 #* tazndis, install, remove or list of NDIS drivers.
5 #*
6 #* This program is a replacement for ndiswrapper utility written by
7 #* Pontus Fuchs and Giridhar Pemmasani.
8 #* Most part of code come from the original ndiswrapper PERL script.
9 #*
10 #* If you need more complexe commands consider to use the original ndiswrapper
11 #* instead.
12 #*
13 #* Copyright (C) 2008 Eric Joseph-Alexandre
14 #* Copyright (C) 2005-2006 Pontus Fuchs, Giridhar Pemmasani
15 #*
16 #*
17 #* This program is free software; you can redistribute it and/or modify
18 #* it under the terms of the GNU General Public License as published by
19 #* the Free Software Foundation; either version 2 of the License, or
20 #* (at your option) any later version.
21 #*
22 #* This program is distributed in the hope that it will be useful,
23 #* but WITHOUT ANY WARRANTY; without even the implied warranty of
24 #* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 #* GNU General Public License for more details.
26 #*
27 #*/
29 $ENV{PATH} = "/sbin:/usr/sbin:$ENV{PATH}";
31 my $WRAP_PCI_BUS = 5;
32 my $WRAP_PCMCIA_BUS = 8;
33 my $WRAP_USB_BUS = 15;
35 my %sections;
36 my %parsed_sections;
37 my $confdir = "/etc/ndiswrapper";
38 my $src_dir;
39 my $driver_name;
40 my @source_disks_files;
42 my $re_dev_id = "([[:xdigit:]]{4})";
43 my $re_sub_dev_conf = "$re_dev_id:$re_dev_id:$re_dev_id:$re_dev_id" .
44 "\.([[:xdigit:]]+)\.conf";
45 my $re_dev_conf = "$re_dev_id:$re_dev_id\.([[:xdigit:]]+)\.conf";
47 # fixup list for parameters.
48 my %param_fixlist = ("EnableRadio|0" => "1",
49 "IBSSGMode|0" => "2",
50 "PrivacyMode|0" => "2",
51 "MapRegisters|256" => "64",
52 "AdhocGMode|1" => "0");
54 if (@ARGV < 1) {
55 usage();
56 exit(1);
57 }
59 my $res;
60 my $dbg_file;
62 $dbg_file = "/dev/null";
64 # "-D" is for development/debugging only
65 if ($ARGV[0] eq "-D") {
66 $dbg_file = "/tmp/ndiswrapper.dbg";
67 $confdir = "/tmp/ndiswrapper";
68 open(DBG, "> $dbg_file") or die "couldn't open $dbg_file: $!";
69 shift;
70 }
72 if ($ARGV[0] eq "-i" and @ARGV == 2) {
73 $res = install($ARGV[1]);
74 } elsif (($ARGV[0] eq "-r") and @ARGV == 2) {
75 $res = remove_driver($ARGV[1]);
76 } elsif ($ARGV[0] eq "-l" and @ARGV == 1) {
77 $res = list_drivers();
78 } elsif ($ARGV[0] eq "-v" and @ARGV == 1) {
79 $res = check_version();
80 } else {
81 usage();
82 }
83 close(DBG);
84 exit($res);
86 sub usage() {
87 print "install/manage Windows drivers for ndiswrapper\n\n" .
88 "usage: ndiswrapper OPTION\n" .
89 "-i inffile install driver described by 'inffile'\n" .
90 "-r driver remove 'driver'\n" .
91 "-l list installed drivers\n" .
92 "-v report version information\n\n" .
93 "If you need more complex operation, you may use ndiswrapper instead.\n" ;
94 }
96 #/*
97 #* Begin of PERL modules substition
98 #*
99 #* Replaced File.pm
101 sub basename(@_){
102 $var = $_[0];
103 $var =~ s#.*/(.*)$#$1#;
104 return $var;
105 }
107 sub dirname {
108 local $var = $_[0];
109 $var =~ s#(.*)/.*$#$1#;
110 return $var;
111 }
113 # delete given single tree with no sub directories.
114 sub rmtree {
115 local $dir = $_[0];
116 opendir(DIR, $dir) or die "couldn't delete $dir: $!\n";
117 @dirs = grep(!/^.{1,2}$/, readdir(DIR));
118 foreach $file (@dirs){
119 unlink "$dir/$file" or die "couldn't delete file $file $!";
120 }
121 if(rmdir "$dir"){
122 return 1;
123 }else{
124 return 0;
125 }
126 }
128 # return current path.
129 sub cwd {
130 local $var;
131 chomp($var = `pwd`);
132 return $var;
133 }
135 #
136 sub copy {
137 local ($file1, $file2) = @_;
138 open (F1, "$file1") or
139 die "couldn't open file $file1 for reading $!\n";
140 open (F2, ">$file2") or
141 die "couldn't open file $file2 for writing $!\n";
142 if ($file1 =~ /\.((bin)|(sys)|(cat))$/) {
143 binmode F1;
144 binmode F2;
145 while (read(F1,$buffer,1)) {
146 print(F2 $buffer);
147 }
148 } else {
149 while (<F1>) {
150 print F2 $_;
151 }
152 }
153 close F1;
154 close F2;
155 }
157 ##
158 ## End of PERL modules substition
159 ##
161 sub remove_driver {
162 my $driver = shift;
163 if (!rmtree("$confdir/$driver", 0, 1)) {
164 warn "couldn't delete $confdir/$driver: $!\n";
165 }
166 return 0;
167 }
169 sub abort {
170 remove_driver($driver_name);
171 exit 1;
172 }
174 sub check_version {
175 my ($utils_version, $module_utils_version, $res);
176 $res = 0;
177 $utils_version = `loadndisdriver -v`;
178 chomp($utils_version);
179 $utils_version =~ s/^version: //;
180 if (length($utils_version) eq 0) {
181 printf "utils version is too old!\n";
182 $res = -1;
183 }
184 $module_utils_version = 0;
185 open(MODINFO, "modinfo ndiswrapper |");
186 while (my $line = <MODINFO>) {
187 if ($line =~ /utils_version:.*read only:\s([0-9\.]+)/) {
188 $module_utils_version = $1;
189 last;
190 }
191 }
192 if ($module_utils_version eq 0) {
193 printf "module version is too old!\n";
194 $res = -1;
195 } elsif ($utils_version ne $module_utils_version) {
196 printf "utils version '%s' is incompatible with utils version needed" .
197 " by driver ('%s')!\n", $utils_version, $module_utils_version;
198 $res = -1;
199 }
200 printf "utils version: '%s', utils version needed by module: '%s'\n",
201 $utils_version, $module_utils_version;
202 printf "module details:\n";
203 system("modinfo ndiswrapper | grep -E '^(version|vermagic|filename)'");
205 if ($res) {
206 printf "\nYou may need to upgrade driver and/or utils to latest " .
207 "versions available at\n" .
208 "http://ndiswrapper.sourceforge.net\n";
209 }
210 return $res;
211 }
213 sub install {
214 my $inf = shift;
215 chomp($inf);
216 $src_dir = dirname($inf);
217 $driver_name = lc(basename($inf));
219 unless ($driver_name =~ s/\.inf$//) {
220 die "install argument must be .inf file\n";
221 }
223 if (! -d $confdir) {
224 mkdir($confdir) or die "couldn't create $confdir: $!";
225 }
226 (-d "$confdir/$driver_name") and
227 die "driver $driver_name is already installed\n";
229 read_sections($inf);
230 parse_section("Strings");
231 parse_section("Version");
232 parse_source_disks_files();
233 mkdir("$confdir/$driver_name") or
234 die "couldn't create $confdir/$driver_name: $!";
235 print "installing $driver_name ...\n";
236 parse_mfr();
237 copy_file(basename($inf), basename($inf));
238 create_fuzzy_conf($driver_name);
239 return 0;
240 }
242 # return lines in section
243 sub get_section {
244 my $name = shift;
245 foreach my $key (keys %sections) {
246 if (lc($key) eq lc($name)) {
247 printf DBG "section: $key\n";
248 return \@{$sections{$key}};
249 }
250 }
251 printf DBG "couldn't find section \"$name\"\n";
252 return 0;
253 }
255 # load inf and split into different sections.
256 sub read_sections {
257 my $filename = shift;
258 open(INF, $filename) or die "couldn't open $filename: $!";
260 my $name = "none";
261 @{$sections{$name}} = ();
262 while (my $line = <INF>) {
263 # convert from unicode
264 $line =~ s/\xff\xfe//;
265 $line =~ s/\0//g;
267 chomp($line);
268 $line = trim($line);
269 next if ($line =~ /^$/);
270 if ($line =~ /^\[(.+)\]/) {
271 $name = $1;
272 @{$sections{$name}} = ();
273 } else {
274 push(@{$sections{$name}}, $line);
275 }
276 }
277 close(INF);
278 foreach $name (keys %sections) {
279 printf DBG "section: %s\n", $name;
280 foreach my $line (@{$sections{$name}}) {
281 printf DBG "%s: %s\n", $name, $line;
282 }
283 }
284 }
286 sub parse_section {
287 my $name = shift;
288 my $lines = get_section($name);
289 if (!$lines) {
290 return;
291 }
292 $parsed_sections{$name} = ();
293 foreach my $line (@{$lines}) {
294 (my $key, my $val) = parse_key_value($line);
295 if ($key) {
296 $val = strip_quotes($val);
297 $parsed_sections{$name}->{$key} = $val;
298 printf DBG "$name: %s = %s\n", $key, $val;
299 }
300 }
301 }
303 sub parse_mfr() {
304 my $lines = get_section("Manufacturer");
305 $lines or die "couldn't get manufacturer section - " .
306 "installation may be incomplete\n";
307 foreach my $line (@{$lines}) {
308 my ($strkey, $val) = parse_key_value($line);
309 if ($strkey) {
310 my ($models, @targets) = split(",", $val);
311 if ($models) {
312 printf DBG "mfr: %s, %s\n", $line, $models;
313 my $target = choose_target_os(@targets);
314 printf DBG "target: '%s'\n", $target;
315 parse_models($models, $target);
316 }
317 }
318 }
319 }
321 sub parse_models {
322 my ($models, $target) = @_;
323 printf DBG "models: target: '%s'.'%s'\n", $models, $target;
324 my $lines = get_target_os_section($models, $target);
325 if (!$lines) {
326 warn "couldn't find models section \"$models\" -\n" .
327 "installation may be incomplete\n";
328 return -1;
329 }
330 foreach my $line (@{$lines}) {
331 $line = del_comment($line);
332 next if (length($line) eq 0);
333 (my $dev_desc, my $val) = parse_key_value($line);
334 my @fields = split(",", $val);
335 if (@fields le 1) {
336 printf "couldn't find install directive: %s\n", $line;
337 next;
338 }
339 my $section = trim($fields[0]);
340 my $hwid = trim($fields[1]);
341 if ($hwid =~ /^%.+%$/) {
342 $hwid = get_string_value($hwid);
343 }
344 # TODO: deal with compatible IDs as hwid?
345 my ($bus_type, $vendor, $device, $subvendor, $subdevice) =
346 parse_hwid($hwid);
347 next if (!$vendor);
348 printf DBG "models: %s, %s, %s\n", $section, $hwid, $vendor;
349 parse_install($section, $target, $bus_type, $vendor, $device,
350 $subvendor, $subdevice);
351 }
352 }
354 sub parse_install {
355 my ($section, $target, $bus_type, $vendor, $device,
356 $subvendor, $subdevice) = @_;
357 my $lines = get_target_os_section($section, $target);
358 if (!$lines) {
359 warn "couldn't find install section \"$section\" -\n" .
360 "installation may be incomplete\n";
361 return -1;
362 }
364 my $filename = "$vendor:$device";
365 if ($subvendor) {
366 $filename .= ":$subvendor:$subdevice"
367 }
368 $filename .= sprintf(".%X.conf", $bus_type);
370 my (@addregs, @copyfiles);
371 foreach my $line (@{$lines}) {
372 $line =~ s/^;\s*//;
373 $line = trim(del_comment($line));
374 my ($key, $val) = parse_key_value($line);
375 my @array;
376 if ($key) {
377 if (lc($key) eq "addreg") {
378 @array = split(",", $val);
379 foreach my $reg (@array) {
380 push @addregs, trim($reg);
381 }
382 } elsif (lc($key) eq "copyfiles") {
383 printf DBG "copyfiles: %s\n", $val;
384 @array = split(",", $val);
385 foreach my $copy_file_dirs (@array) {
386 my @copy_sec = split(",", $copy_file_dirs);
387 foreach my $file (@copy_sec) {
388 push @copyfiles, trim($file);
389 }
390 }
391 } elsif (lc($key) eq "bustype") {
392 printf DBG "bustype: %s\n", $val;
393 $bus_type = $val;
394 }
395 }
396 }
398 open(CONF, ">$confdir/$driver_name/$filename") or
399 die "couldn't create file $confdir/$driver_name/$filename: $!";
401 printf CONF "sys_files|";
402 foreach my $file (@copyfiles) {
403 parse_copy_file($file);
404 }
405 printf CONF "\n";
407 my $version = get_section_value("Version", "DriverVer");
408 my $provider = get_section_value("Version", "Provider");
409 my $classguid = get_section_value("Version", "ClassGUID");
410 my $providerstring = trim(strip_quotes(get_string_value(trim($provider))));
411 $classguid =~ s/^\s*{//;
412 $classguid =~ s/}\s*$//;
414 printf CONF "NdisVersion|0x50001\n";
415 printf CONF "Environment|1\n";
416 printf CONF "class_guid|%s\n", $classguid;
417 printf CONF "driver_version|%s,%s\n", $providerstring, $version;
418 printf CONF "BusType|%s\n", $bus_type;
419 printf CONF "SlotNumber|01\n";
420 printf CONF "NetCfgInstanceId|{28022A01-1234-5678-ABCDE-123813291A00}\n";
421 printf CONF "\n";
422 close(CONF);
424 open(CONF, "|sort|uniq >>$confdir/$driver_name/$filename") or
425 die "couldn't create file $confdir/$driver_name/$filename: $!";
427 foreach my $reg (@addregs) {
428 parse_registry($reg);
429 }
430 close(CONF);
431 }
433 sub parse_registry {
434 my ($reg, $conf) = @_;
435 my $lines = get_section($reg);
436 if (!$lines) {
437 warn "couldn't find section \"$reg\" -\n" .
438 "installation may be incomplete\n";
439 return -1;
440 }
442 my $driver_desc = 0;
443 foreach my $line (@{$lines}) {
444 $line = del_comment($line);
445 my @fields = split(",", $line);
446 next if (@fields lt 4);
447 my $value;
448 my $param = trim($fields[1]);
449 if ($param =~ /^ndi\\/i) {
450 if ($param =~ /^ndi\\params\\(.+)/i) {
451 $param = strip_quotes(trim($1));
452 $param =~ s/\\.*$//;
453 next if (lc(trim($fields[2])) ne "default");
454 $value = strip_quotes(trim($fields[4]));
455 } else {
456 printf DBG "ignoring parameter $line\n";
457 next;
458 }
459 } else {
460 $param = strip_quotes(trim($fields[2]));
461 next if (length($param) eq 0);
462 $value = strip_quotes(trim($fields[4]));
463 }
464 $value = get_string_value($value);
465 if (length($param) gt 0) {
466 if ($param_fixlist{"$param|$value"}) {
467 my $orig_value = $value;
468 $value = $param_fixlist{"$param|$value"};
469 printf "forcing parameter $param from $orig_value to $value\n";
470 }
471 printf CONF "%s|%s\n", $param, $value;
472 if ($param =~ /^DriverDesc$/) {
473 $driver_desc = 1;
474 }
475 }
476 }
477 if ($driver_desc == 0) {
478 printf CONF "DriverDesc|NDIS Network Adapter\n";
479 }
480 }
482 sub parse_copy_file {
483 my $copy_name = shift;
485 if ($copy_name =~ /^\@/) {
486 $copy_name =~ s/^\@//;
487 $copy_name = trim($copy_name);
488 if (valid_copy_file_name($copy_name)) {
489 return copy_file($copy_name, $copy_name);
490 }
491 }
493 my $lines = get_section($copy_name);
494 if (!$lines) {
495 warn "couldn't find section \"$copy_name\" -\n" .
496 "installation may be incomplete\n";
497 return -1;
498 }
499 foreach my $line (@{$lines}) {
500 $line = trim($line);
502 # some inf files have file names commented out; get file names from them
503 $line =~ s/^\s*;//;
504 my @files = split(",", $line);
505 if (@files == 0) {
506 printf DBG "copyfiles section $copy_name has no files\n";
507 return -1;
508 }
509 my $src, my $dst;
510 if (@files > 1 and length(trim($files[1])) > 0) {
511 $src = $files[1];
512 if (length(trim($files[0])) > 0) {
513 $dst = $files[0];
514 } else {
515 $dst = $src;
516 }
517 } else {
518 $src = $files[0];
519 $dst = $src;
520 }
521 $src =~ s/^.*\\//;
522 $dst =~ s/^.*\\//;
523 printf DBG "src: '%s', dst: '%s'\n", $src, $dst;
524 $src = trim(del_comment($src));
525 next if (length($src) eq 0);
526 if (valid_copy_file_name($src)) {
527 $dst = trim(del_comment($dst));
528 printf DBG "src: '%s', dst: '%s'\n", $src, $dst;
529 copy_file($src, $dst);
530 } else {
531 printf DBG "invalid file '%s' ignored\n", $src;
532 }
533 }
534 return 0;
535 }
537 sub parse_hwid {
538 my $hwid = uc(shift);
539 if ($hwid =~ /(PCI\\)?VEN_(\w+)&DEV_(\w+)&SUBSYS_(\w{4})(\S{4})/) {
540 return ($WRAP_PCI_BUS, $2, $3, $4, $5);
541 } elsif ($hwid =~ /(PCI\\)?VEN_(\w+)&DEV_(\w+)/) {
542 return ($WRAP_PCI_BUS, $2, $3, 0, 0);
543 } elsif ($hwid =~ /(USB\\)?VID_(\w+)&PID_(\w+)/) {
544 return ($WRAP_USB_BUS, $2, $3, 0, 0);
545 } else {
546 return 0;
547 }
548 }
550 sub parse_key_value {
551 my $line = shift;
553 $line = del_comment($line);
554 if ($line =~ /([^=]+)=(.+)/) {
555 return (trim($1), trim($2));
556 } else {
557 return 0;
558 }
559 }
561 sub choose_target_os {
562 my @targets = @_;
563 my $arch = `uname -m`;
564 chomp($arch);
565 printf DBG "arch: %s\n", $arch;
566 if ($arch =~ /64$/) {
567 $arch = "amd64";
568 } else {
569 $arch = "x86";
570 }
571 printf DBG "arch: %s\n", $arch;
572 my @prefs = ("NT($arch)\.5\.1", "NT($arch)\.5", "NT($arch)",
573 "NT\.5\.1", "NT\.5", "NT");
574 foreach my $pref (@prefs) {
575 foreach my $target (@targets) {
576 $target = trim($target);
577 printf DBG "target: '%s', pref: '%s'\n", $target, $pref;
578 if ($target =~ /NT((amd64)|(x86))/i) {
579 printf DBG "target arch: '%s'\n", $1;
580 next if ($1 !~ /$arch/i);
581 }
582 if ($target =~ /$pref/i) {
583 return $target;
584 }
585 }
586 }
587 return "";
588 }
590 sub get_target_os_section {
591 my ($section, $target) = @_;
592 my $lines;
594 chomp($section);
595 $section =~ s/^\s*"\s*//;
596 $section =~ s/\s*"\s*$//;
597 printf DBG "section: \"%s\", target: \"%s\"\n", $section, $target;
599 if (length($target) gt 0) {
600 $lines = get_section($section . "." . $target);
601 return $lines if ($lines);
602 }
604 my $arch = `uname -m`;
605 chomp($arch);
606 printf DBG "arch: %s\n", $arch;
607 if ($arch =~ /64$/) {
608 $arch = "AMD64";
609 } else {
610 $arch = "X86";
611 }
612 printf DBG "arch: %s\n", $arch;
614 my @prefs = ("NT$arch.5.1", "NT$arch.5", "NT$arch",
615 "NT.5.1", "NT.5", "NT");
616 foreach my $pref (@prefs) {
617 $lines = get_section($section . "." . $pref);
618 return $lines if ($lines);
619 }
620 $lines = get_section($section);
621 return $lines if ($lines);
623 printf DBG "couldn't find section \"$section\" for \"$arch\"\n";
624 return 0;
625 }
627 sub get_section_value {
628 (my $section, my $name) = @_;
629 return $parsed_sections{$section}->{$name};
630 }
632 sub get_string_value {
633 my $key = shift;
634 if ($key =~ /%(.+)%/) {
635 $key = $1;
636 return get_section_value("Strings", $key);
637 } else {
638 return $key;
639 }
640 }
642 sub copy_file {
643 my ($src, $dst) = @_;
645 # ignore files not needed
646 return 0 if (lc($src) =~ /\.((exe)|(dll)|(cpl)|(hlp))$/);
647 my $real_file = get_file($src);
648 if (length($real_file) gt 0) {
649 $dst = lc($dst);
650 printf DBG "copying \"$src_dir/$real_file\" to " .
651 "\"$confdir/$driver_name/$dst\"\n";
652 copy("$src_dir/$real_file", "$confdir/$driver_name/$dst") or
653 warn "couldn't copy \"$src_dir/$real_file\" to " .
654 "\"$confdir/$driver_name\": $! -\n" .
655 "installation may be incomplete\n";
656 printf DBG "chmod: $confdir/$driver_name/$dst\n";
657 chmod(0644, "$confdir/$driver_name/$dst");
658 if ($dst =~ /\.sys$/) {
659 printf CONF "%s ", $dst;
660 }
661 } else {
662 warn "couldn't find \"$src\" in \"$src_dir\"; make sure " .
663 "all driver files, including .inf, .sys (and any firmware files) " .
664 "are in \"$src_dir\" -\n" .
665 "installation may be incomplete\n";
666 }
667 }
670 # for conf files with subvendor and subdevice, create conf files with just
671 # vendor and device
672 sub create_fuzzy_conf {
673 my $driver = shift;
674 my $cwd = cwd();
675 chdir("$confdir/$driver") or die "couldn't chdir to $confdir/$driver: $!";
676 open(LS, "ls -1 . |") or die "couldn't open $confdir/$driver: $!";
677 while (my $file = <LS>) {
678 chomp($file);
679 if ($file =~ /$re_sub_dev_conf/) {
680 my $fuzzy_file = "$1:$2.$5.conf";
681 printf DBG "file: $file, fuzzy file: $fuzzy_file\n";
682 if (! -e "$confdir/$driver/$fuzzy_file") {
683 symlink("$file", "$fuzzy_file") or
684 warn "couldn't link $confdir/$driver/$file " .
685 "to $confdir/$driver/$fuzzy_file: $!\n";
686 }
687 }
688 }
689 close(LS);
690 chdir($cwd) or warn "couldn't chdir to $cwd: $!";
691 return 0;
692 }
694 # find a file in a case-insensitive way.
695 sub get_file {
696 my $file = lc(shift);
697 if (opendir(DIR, "$src_dir")) {
698 my @allfiles = readdir(DIR);
699 foreach my $real_file (@allfiles) {
700 if (lc($real_file) eq $file) {
701 closedir(DIR);
702 return $real_file;
703 }
704 }
705 closedir(DIR);
706 } else {
707 warn "couldn't open \"$src_dir\": $! -\n" .
708 "installation may be incomplete\n";
709 }
710 return "";
711 }
713 sub strip_quotes {
714 my $s = shift;
715 $s =~ s/"(.*)"/$1/;
716 return $s;
717 }
719 sub del_comment {
720 my $s = shift;
721 $s =~ s/;.*//;
722 return $s;
723 }
725 # remove whitsepace at front and end.
726 sub trim {
727 my $s = shift;
728 $s =~ s/^\s*//;
729 $s =~ s/\s*$//;
730 return $s;
731 }
733 sub valid_copy_file_name {
734 my $file = shift;
735 $file = lc($file);
736 printf DBG "file name: %s\n", $file;
737 foreach my $disk_file (@source_disks_files) {
738 return 1 if ($file eq $disk_file);
739 }
740 # some inf files may not have SourceDisksFiles section, so use
741 # known file names
742 return 1 if ($file =~ /\.((sys)|(bin)|(out))$/);
743 return 0;
744 }
746 sub parse_source_disks_files {
747 my $lines = get_source_disks_files();
748 if ($lines) {
749 foreach my $line (@{$lines}) {
750 $line = del_comment($line);
751 next if (length($line) eq 0);
752 my @file = split("=", $line);
753 next if (@file eq 0 or length($file[0] eq 0));
754 printf DBG "source disk file: \"%s\"\n", trim($file[0]);
755 push (@source_disks_files, lc(trim($file[0])));
756 }
757 } else {
758 warn "couldn't find SourceDisksFiles section - " .
759 "continuing anyway...\n";
760 }
761 }
763 sub get_source_disks_files {
764 my $arch = `uname -m`;
765 chomp($arch);
766 if ($arch =~ /64$/) {
767 $arch = "AMD64";
768 } else {
769 $arch = "X86";
770 }
772 my $lines = get_section("SourceDisksFiles." . $arch);
773 return $lines if ($lines);
775 $lines = get_section("SourceDisksFiles");
776 return $lines if ($lines);
778 return 0;
779 }
781 sub device_driver_alias {
782 my ($devid, $driver) = @_;
783 my $done = 0;
785 $devid = uc($devid);
786 if (!($devid =~ /^$re_dev_id:$re_dev_id$/)) {
787 printf "'$devid' is not a valid device ID\n";
788 return 1;
789 }
790 open(LS, "ls -1 $confdir/$driver/ |") or
791 die "couldn't open $confdir/$driver: $!";
793 while (my $f = <LS>) {
794 chomp($f);
795 if ($f =~ /\.([[:xdigit:]]+)\.conf$/) {
796 if (stat("$confdir/$driver/$devid.$1.conf")) {
797 printf "Driver '$driver' is already used for '$devid'\n";
798 $done = 1;
799 last;
800 }
801 if (symlink("$f", "$confdir/$driver/$devid.$1.conf")) {
802 printf "WARNING: Driver '$driver' will be used for '$devid'\n" .
803 "This is safe _only_ if driver $driver is meant for " .
804 "chip in device $devid\n";
805 $done = 1;
806 last;
807 } else {
808 warn "couldn't create symlink for \"$f\": $! -\n" .
809 "installation may be incomplete\n";
810 }
811 }
812 }
813 close(LS);
814 if ($done == 0) {
815 printf "driver '$driver' is not installed (properly)!\n";
816 return 1;
817 }
818 return 0;
819 }
821 sub list_drivers {
822 my $cards = get_cards();
824 open(LS, "/bin/ls -1 $confdir|") or die "couldn't open $confdir: $!";
825 while (my $driver = <LS>) {
826 chomp($driver);
827 if (-e "$confdir/$driver") {
828 printf "%s : %s\n", $driver, install_status($cards, $driver);
829 }
830 }
831 close(LS);
832 return 0;
833 }
836 sub get_cards {
837 #01:00.0 Class 0300: 1002:4c66 (rev 01)
838 # Subsystem: 1043:1732
839 my @cards = ();
840 if (open(LSPCI, "/usr/bin/lspci -vn|")) {
841 my $card;
842 while (my $line = <LSPCI>) {
843 if ($line =~ /^[0-9a-f]+.+\s$re_dev_id:$re_dev_id/) {
844 $card = {vendor => uc($1), device => uc($2)};
845 printf DBG "card: %s, %s\n", $1, $2;
846 } elsif ($line =~ /.+Subsystem:\s$re_dev_id:$re_dev_id/) {
847 $card->{subvendor} = uc($1);
848 $card->{subdevice} = uc($2);
849 printf DBG "sub: %s, %s\n", $1, $2;
850 push(@cards, $card);
851 }
852 }
853 close(LSPCI);
854 }
856 if (open(LSUSB, "lsusb |")) {
857 my $card;
858 while (my $line = <LSUSB>) {
859 if ($line =~ /.+: ID\s$re_dev_id:$re_dev_id/) {
860 $card = {vendor => uc($1), device => uc($2)};
861 push(@cards, $card);
862 }
863 }
864 close(LSUSB);
865 }
866 return \@cards;
867 }
869 sub install_status {
870 my ($cards, $driver) = @_;
872 if (!$cards or !$driver) {
873 return;
874 }
876 my ($sys, $conf, $inf);
877 my ($vendor, $device, $subvendor, $subdevice, $busid, $ret);
879 $sys = $conf = $inf = 0;
880 open(LS2, "/bin/ls -1 $confdir/$driver|") or
881 die "couldn't open $confdir/$driver: $!";
882 while (my $file = <LS2>) {
883 chomp($file);
884 if ($file =~ /\.sys$/) {
885 $sys = 1;
886 } elsif ($file =~ /\.inf$/) {
887 $inf = 1;
888 } elsif ($file =~ /^$re_sub_dev_conf$/) {
889 $busid = hex($5);
890 $conf = 1 if ($busid eq $WRAP_PCI_BUS);
891 } elsif ($file =~ /^$re_dev_conf$/) {
892 $busid = hex($3);
893 $conf = 1 if ($busid eq $WRAP_USB_BUS or $busid eq 0 or
894 $busid eq $WRAP_PCI_BUS);
895 }
896 }
897 close(LS2);
898 printf DBG "status: $sys, $inf, $conf\n";
899 if ($sys eq 0 or $inf eq 0 or $conf eq 0) {
900 $ret = "invalid driver!";
901 return $ret;
902 }
903 $ret = "driver installed";
904 open(LS2, "/bin/ls -1 $confdir/$driver|") or
905 die "couldn't open $confdir/$driver: $!";
907 while (my $file = <LS2>) {
908 chomp($file);
909 next if ($file !~ /\.conf$/);
910 $conf = 0;
911 if ($file =~ /^$re_sub_dev_conf$/) {
912 ($vendor, $device, $subvendor, $subdevice, $busid) =
913 (uc($1), uc($2), uc($3), uc($4), hex($5));
914 $conf = 1;
915 foreach my $card (@{$cards}) {
916 if ($card->{vendor} eq $vendor and
917 $card->{device} eq $device and
918 $card->{subvendor} eq $subvendor and
919 $card->{subdevice} eq $subdevice and
920 $busid eq $WRAP_PCI_BUS) {
921 $ret .= "\n\tdevice ($vendor:$device" .
922 ":$subvendor:$subdevice) present";
923 $conf = 2;
924 last;
925 }
926 }
927 } elsif ($file =~ /^$re_dev_conf/) {
928 ($vendor, $device, $subvendor, $subdevice, $busid) =
929 (uc($1), uc($2), "\\*", "\\*", hex($3));
930 $conf = 1;
931 foreach my $card (@{$cards}) {
932 if ($card->{vendor} eq $vendor and
933 $card->{device} eq $device and
934 ($busid eq $WRAP_USB_BUS or $busid eq 0 or
935 $busid eq $WRAP_PCI_BUS)) {
936 $ret .= "\n\tdevice ($vendor:$device) present";
937 $conf = 2;
938 last;
939 }
940 }
941 }
942 next if ($conf le 1);
943 # find if kernel knows of an alternate driver for this device
944 my $devstring;
945 if ($busid eq $WRAP_USB_BUS or $busid eq 0) {
946 $devstring = sprintf("usb:v%sp%sd", $vendor, $device);
947 } elsif ($busid eq $WRAP_PCI_BUS) {
948 $devstring = sprintf("pci:v0000%sd0000%ssv", $vendor, $device);
949 } else {
950 next;
951 }
952 open(MODPROBE, "modprobe -c|") or next;
953 while (my $line = <MODPROBE>) {
954 my $alt;
955 chomp($line);
956 next if $line !~ /$devstring/;
957 $alt = (split(' ', $line))[-1];
958 chomp($alt);
959 if (length($alt) gt 0 and $alt ne "ndiswrapper") {
960 $ret .= " (alternate driver: $alt)";
961 last;
962 }
963 }
964 close(MODPROBE);
965 }
966 close(LS2);
967 printf DBG "driver: $driver, $ret\n";
968 return $ret;
969 }
971 ## Local Variables: ##
972 ## cperl-indent-level: 4 ##
973 ## End: ##