diff options
Diffstat (limited to 'perl-install/detect_devices.pm')
-rw-r--r-- | perl-install/detect_devices.pm | 324 |
1 files changed, 254 insertions, 70 deletions
diff --git a/perl-install/detect_devices.pm b/perl-install/detect_devices.pm index 8f1fac97d..79bfedb71 100644 --- a/perl-install/detect_devices.pm +++ b/perl-install/detect_devices.pm @@ -1,25 +1,33 @@ -package detect_devices; +package detect_devices; # $Id$ use diagnostics; use strict; +#-###################################################################################### +#- misc imports +#-###################################################################################### use log; -use common qw(:common :file); +use common qw(:common :file :functional); +use devices; use c; +#-##################################################################################### +#- Globals +#-##################################################################################### +my @netdevices = map { my $l = $_; map { "$l$_" } (0..3) } qw(eth tr fddi plip); +my %serialprobe = (); +my $usb_interface = undef; -my $scsiDeviceAvailable; -my $CSADeviceAvailable; - -1; - +#-###################################################################################### +#- Functions +#-###################################################################################### sub get { - # Detect the default BIOS boot harddrive is kind of tricky. We may have IDE, - # SCSI and RAID devices on the same machine. From what I see so far, the default - # BIOS boot harddrive will be - # 1. The first IDE device if IDE exists. Or - # 2. The first SCSI device if SCSI exists. Or - # 3. The first RAID device if RAID exists. + #- Detect the default BIOS boot harddrive is kind of tricky. We may have IDE, + #- SCSI and RAID devices on the same machine. From what I see so far, the default + #- BIOS boot harddrive will be + #- 1. The first IDE device if IDE exists. Or + #- 2. The first SCSI device if SCSI exists. Or + #- 3. The first RAID device if RAID exists. map { &{$_->[0]}() ? &{$_->[1]}() : () } [ \&hasIDE, \&getIDE ], @@ -27,52 +35,88 @@ sub get { [ \&hasDAC960, \&getDAC960 ], [ \&hasCompaqSmartArray, \&getCompaqSmartArray ]; } -sub hds() { grep { $_->{type} eq 'hd' } get(); } -sub cdroms() { grep { $_->{type} eq 'cdrom' } get(); } +sub hds() { grep { $_->{type} eq 'hd' && ($::isStandalone || !isRemovableDrive($_)) } get(); } +sub zips() { grep { $_->{type} =~ /.d/ && isZipDrive($_) } get(); } +sub ide_zips() { grep { $_->{type} =~ /.d/ && isZipDrive($_) } getIDE(); } +#-sub jazzs() { grep { $_->{type} =~ /.d/ && isJazDrive($_) } get(); } +sub ls120s() { grep { $_->{type} =~ /.d/ && isLS120Drive($_) } get(); } +sub usbfdus() { grep { $_->{type} =~ /.d/ && isUSBFDUDrive($_) } get(); } +sub cdroms() { + my @l = grep { $_->{type} eq 'cdrom' } get(); + if (my @l2 = IDEburners()) { + require modules; + modules::add_alias('scsi_hostadapter', 'ide-scsi'); + my $nb = 1 + max(-1, map { $_->{device} =~ /scd (\d+)/x } @l); + foreach my $i (@l2) { + log::l("IDEBurner: $i->{device}"); + my ($e) = grep { $_->{device} eq $i->{device} } @l; + $e->{device} = "scd" . $nb++; + } + } + @l; +} +sub burners { grep { isBurner($_->{device}) } cdroms() } +sub IDEburners { grep { $_->{type} eq 'cdrom' && isBurner($_->{device}) } getIDE() } + +sub floppies() { + require modules; + my @ide = map { $_->{device} } ls120s() and modules::load("ide-floppy"); + my @scsi = map { $_->{device} } usbfdus(); + (@ide, @scsi, grep { tryOpen($_) } qw(fd0 fd1)); +} +sub floppy { first(floppies()) } +#- example ls120, model = "LS-120 SLIM 02 UHD Floppy" + +sub isBurner { my $f = tryOpen($_[0]); $f && c::isBurner(fileno($f)) } +sub isZipDrive { $_[0]->{info} =~ /ZIP\s+\d+/ } #- accept ZIP 100, untested for bigger ZIP drive. +#-sub isJazzDrive { $_[0]->{info} =~ /JAZZ?\s+/ } #- untested. +sub isLS120Drive { $_[0]->{info} =~ /LS-?120|144MB/ } +sub isUSBFDUDrive { $_[0]->{info} =~ /USB-?FDU/ } +sub isRemovableDrive { &isZipDrive || &isLS120Drive || &isUSBFDUDrive } #-or &isJazzDrive } sub hasSCSI() { - defined $scsiDeviceAvailable and return $scsiDeviceAvailable; - local *F; - open F, "/proc/scsi/scsi" or log::l("failed to open /proc/scsi/scsi: $!"), return 0; - foreach (<F>) { - /devices: none/ and log::l("no scsi devices are available"), return $scsiDeviceAvailable = 0; + local *F; open F, "/proc/scsi/scsi" or return 0; + local $_; + while (<F>) { + /devices: none/ and log::l("no scsi devices are available"), return 0; } - log::l("scsi devices are available"); - $scsiDeviceAvailable = 1; +#- log::l("scsi devices are available"); + 1; } -sub hasIDE() { 1 } +sub hasIDE() { -e "/proc/ide" } sub hasDAC960() { 1 } +sub hasCompaqSmartArray() { -r "/proc/array/ida0" } -sub hasCompaqSmartArray() { - defined $CSADeviceAvailable and return $CSADeviceAvailable; - -r "/proc/array/ida0" or log::l("failed to open /proc/array/ida0: $!"), return $CSADeviceAvailable = 0; - log::l("Compaq Smart Array controllers available"); - $CSADeviceAvailable = 1; +sub isFloppyOrHD { + my ($dev) = @_; + require partition_table_raw; + my $geom = partition_table_raw::get_geometry(devices::make($dev)); + $geom->{totalsectors} < 10 << 11 ? 'floppy' : 'hd'; } sub getSCSI() { my @drives; my ($driveNum, $cdromNum, $tapeNum) = qw(0 0 0); - my $err = sub { chop; log::l("unexpected line in /proc/scsi/scsi: $_"); error() }; + my $err = sub { chop; die "unexpected line in /proc/scsi/scsi: $_"; }; local $_; local *F; - open F, "/proc/scsi/scsi" or return &$err(); - $_ = <F>; /^Attached devices:/ or return &$err(); + open F, "/proc/scsi/scsi" or die "failed to open /proc/scsi/scsi"; + local $_ = <F>; /^Attached devices:/ or return &$err(); while ($_ = <F>) { my ($id) = /^Host:.*?Id: (\d+)/ or return &$err(); $_ = <F>; my ($vendor, $model) = /^\s*Vendor:\s*(.*?)\s+Model:\s*(.*?)\s+Rev:/ or return &$err(); $_ = <F>; my ($type) = /^\s*Type:\s*(.*)/ or &$err(); my $device; - if ($type =~ /Direct-Access/) { - $type = 'hd'; + if ($type =~ /Direct-Access/) { #- what about LS-120 floppy drive, assuming there are Direct-Access... $device = "sd" . chr($driveNum++ + ord('a')); + $type = isFloppyOrHD($device); } elsif ($type =~ /Sequential-Access/) { - $type = 'tape'; $device = "st" . $tapeNum++; + $type = 'tape'; } elsif ($type =~ /CD-ROM/) { - $type = 'cdrom'; $device = "scd" . $cdromNum++; + $type = 'cdrom'; } $device and push @drives, { device => $device, type => $type, info => "$vendor $model", id => $id, bus => 0 }; } @@ -82,10 +126,11 @@ sub getSCSI() { sub getIDE() { my @idi; - -r "/proc/ide" or die "sorry, /proc/ide not available, seems like you have a pre-2.2 kernel\n => not handled yet :("; + #- what about a system with absolutely no IDE on it, like some sparc machine. + hasIDE() or return (); - # Great. 2.2 kernel, things are much easier and less error prone. - foreach my $d (glob_('/proc/ide/hd*')) { + #- Great. 2.2 kernel, things are much easier and less error prone. + foreach my $d (sort @{[glob_('/proc/ide/hd*')]}) { my ($t) = chop_(cat_("$d/media")); my $type = $ {{disk => 'hd', cdrom => 'cdrom', tape => 'tape', floppy => 'fd'}}{$t} or next; my ($info) = chop_(cat_("$d/model")); $info ||= "(none)"; @@ -96,56 +141,195 @@ sub getIDE() { @idi; } - sub getCompaqSmartArray() { my @idi; my $f; for (my $i = 0; -r ($f = "/proc/array/ida$i"); $i++) { - local *F; - open F, $f or die; - local $_ = <F>; - my ($name) = m|ida/(.*?):| or next; - push @idi, { device => $name, info => "Compaq RAID logical disk", type => 'hd' }; + foreach (cat_($f)) { + if (m|^(ida/.*?):|) { + push @idi, { device => $1, info => "Compaq RAID logical disk", type => 'hd' }; + last; + } + } } @idi; } sub getDAC960() { - my @idi; - my $file = "/var/log/dmesg"; - -r $file or $file = "/tmp/syslog"; + my %idi; + + #- We are looking for lines of this format:DAC960#0: + #- /dev/rd/c0d0: RAID-7, Online, 17928192 blocks, Write Thru0123456790123456789012 + foreach (syslog()) { + my ($device, $info) = m|/dev/(rd/.*?): (.*?),| or next; + $idi{$device} = { info => $info, type => 'hd', device => $device }; + log::l("DAC960: $device ($info)"); + } + values %idi; +} + +sub getNet() { + grep { !($::isStandalone && /plip/) && c::hasNetDevice($_) } @netdevices; +} + +# pci_probing::main::probe with $probe_type is unsafe for pci! (bug in kernel&hardware) +# get_pcmcia_devices provides field "device", used in network.pm +# => probeall with $probe_type is unsafe +sub probeall { + my ($probe_type) = @_; + require pci_probing::main; + require sbus_probing::main; + require modules; + pci_probing::main::probe($probe_type), sbus_probing::main::probe(), modules::get_pcmcia_devices(); +} +sub matching_desc { + my ($regexp) = @_; + grep { $_->{description} =~ /$regexp/i } probeall(); +} +sub stringlist { + map { " $_->{description} ($_->{type} $_->{driver})" . ($_->{subid} ? sprintf(" SubVendor=0x%04x SubDevice=0x%04x", $_->{subvendor}, $_->{subid}) : '') } probeall(1); +} +sub check { + my ($l) = @_; + my $ok = $l->{driver} !~ /(unknown|ignore)/; + $ok or log::l("skipping $l->{description}, no module available (if you know one, please mail bugs\@linux-mandrake.com)"); + $ok +} + + +sub tryOpen($) { + local *F; + sysopen F, devices::make($_[0]), c::O_NONBLOCK() and *F; +} +sub tryWrite($) { local *F; - open F, $file or die "Failed to open $file: $!"; - - # We are looking for lines of this format:DAC960#0: - # /dev/rd/c0d0: RAID-7, Online, 17928192 blocks, Write Thru0123456790123456789012 - foreach (<F>) { - my ($devicename, $info) = m|/dev/rd/(.*?): (.*?),| or next; - push @idi, { info => $info, type => 'hd', devicename => $devicename }; - log::l("DAC960: $devicename: $info"); + sysopen F, devices::make($_[0]), 1 | c::O_NONBLOCK() and *F; +} + +sub syslog { + -r "/tmp/syslog" and return map { /<\d+>(.*)/ } cat_("/tmp/syslog"); + `dmesg`; +} + +sub hasUsb { + my ($class, $prot) = @_; + foreach (cat_("/proc/bus/usb/devices")) { + if (/^P/ .. /^I/) { + my ($c, $p) = /Cls=(\d+).*Prot=(\d+)/; + $c == $class && ($prot < 0 || $prot == $p) and log::l("found usb $c $p"), return 1; + } } - @idi; + 0; } +sub hasUsbKeyboard { hasUsb(3, 1) } +sub hasUsbMouse { hasUsb(3, 2) } +sub hasUsbZip { hasUsb(8, -1) } +sub hasSMP { c::detectSMP() } -sub getNet() { - # I should probably ask which device to use if multiple ones are available -- oh well :-( - foreach (qw(eth0 tr0 plip0 plip1 plip2 fddi0)) { - hasNetDevice($_) and log::l("$_ is available -- using it for networking"), return $_; +sub hasUltra66 { + #- keep it BUT DO NOT USE IT as now included in kernel. + cat_("/proc/cmdline") =~ /(ide2=(\S+)(\s+ide3=(\S+))?)/ and return $1; + + my @l = map { $_->{verbatim} } matching_desc('HPT|Ultra66') or return; + + my $ide = sprintf "ide2=0x%x,0x%x ide3=0x%x,0x%x", + @l == 2 ? + (map_index { hex($_) + (odd($::i) ? 1 : -1) } map { (split ' ')[3..4] } @l) : + (map_index { hex($_) + (odd($::i) ? 1 : -1) } map { (split ' ')[3..6] } @l); + + log::l("HPT|Ultra66: found $ide"); + $ide; +} + +sub whatParport() { + my @res =(); + foreach (0..3) { + my $elem = {}; + local *F; open F, "/proc/parport/$_/autoprobe" or next; + local $_; + while (<F>) { $elem->{$1} = $2 if /(.*):(.*);/ } + push @res, { port => "/dev/lp$_", val => $elem}; + } + @res; +} + +sub whatUsbport() { + my ($i, $elem, @res) = (0, {}); + local *F; open F, "/proc/bus/usb/devices" or return; + local $_; + while (<F>) { + $elem->{$1} = $2 if /S:\s+(.*)=(.*\S)/; + if (/I:.*Driver=(printer|usblp)/ && $elem->{Manufacturer} && $elem->{Product}) { + my $MF = ${{ 'Hewlett-Packard' => 'HP' }}{$elem->{Manufacturer}} || $elem->{Manufacturer}; + push @res, { port => "/dev/usb/lp$i", val => { CLASS => 'PRINTER', + MODEL => $elem->{Product}, + MANUFACTURER => $elem->{Manufacturer}, + DESCRIPTION => "$MF $elem->{Product}", + }}; + $i++; $elem = {}; #- try next one, but blank what has been probed. + } } - undef; + @res; } -sub getPlip() { - foreach (0..2) { - hasNetDevice("plip$_") and log::l("plip$_ will be used for PLIP"), return "plip$_"; + +#-CLASS:PRINTER; +#-MODEL:HP LaserJet 1100; +#-MANUFACTURER:Hewlett-Packard; +#-DESCRIPTION:HP LaserJet 1100 Printer; +#-COMMAND SET:MLC,PCL,PJL; +sub whatPrinter() { + my @res = (whatParport(), whatUsbport()); + grep { $_->{val}{CLASS} eq "PRINTER"} @res; +} + +sub whatPrinterPort() { + grep { tryWrite($_)} qw(/dev/lp0 /dev/lp1 /dev/lp2 /dev/usb/lp0); +} + +sub probeSerialDevices { + #- make sure the device are created before probing. + foreach (0..3) { devices::make("/dev/ttyS$_") } + + #- for device already probed, we can safely (assuming device are + #- not moved during install :-) + #- include /dev/mouse device if using an X server. + -d "/var/lock" or mkdir "/var/lock", 0755; + -l "/dev/mouse" and $serialprobe{"/dev/" . readlink "/dev/mouse"} = undef; + foreach (keys %serialprobe) { m|^/dev/(.*)| and touch "/var/lock/LCK..$1" } + + print STDERR "Please wait while probing serial ports...\n"; + #- start probing all serial ports... really faster than before ... + #- ... but still take some time :-) + local *F; open F, "serial_probe 2>/dev/null |"; + local $_; + my %current = (); while (<F>) { + $serialprobe{$current{DEVICE}} = { %current } and %current = () if /^\s*$/ && $current{DEVICE}; + $current{$1} = $2 if /^([^=]+)=(.*?)\s*$/; } - undef; + close F; + + foreach (values %serialprobe) { + $_->{DESCRIPTION} =~ /modem/i and $_->{CLASS} = 'MODEM'; #- hack to make sure a modem is detected. + $_->{DESCRIPTION} =~ /olitec/i and $_->{CLASS} = 'MODEM'; #- hack to make sure such modem gets detected. + log::l("probed $_->{DESCRIPTION} of class $_->{CLASS} on device $_->{DEVICE}"); + } +} + +sub probeSerial($) { $serialprobe{$_[0]} } + +sub hasModem($) { + $serialprobe{$_[0]} and $serialprobe{$_[0]}{CLASS} eq 'MODEM' and $serialprobe{$_[0]}{DESCRIPTION}; +} + +sub hasMousePS2 { + my $t; sysread(tryOpen($_[0]) || return, $t, 256) != 1 || $t ne "\xFE"; } -sub hasNet() { goto &getNet } -sub hasPlip() { goto &getPlip } -sub hasEthernet() { hasNetDevice("eth0"); } -sub hasTokenRing() { hasNetDevice("tr0"); } -sub hasNetDevice($) { c::hasNetDevice($_[0]) } +#-###################################################################################### +#- Wonderful perl :( +#-###################################################################################### +1; # + |