wok view tazndis/stuff/tazndis @ rev 8435

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