wok view tazndis/stuff/tazndis @ rev 1910

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