wok view tazndis/stuff/tazndis @ rev 1941

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