diff options
Diffstat (limited to 'perl-install/detect_devices.pm')
-rw-r--r-- | perl-install/detect_devices.pm | 477 |
1 files changed, 270 insertions, 207 deletions
diff --git a/perl-install/detect_devices.pm b/perl-install/detect_devices.pm index 1cbe8bd76..4340a9d3f 100644 --- a/perl-install/detect_devices.pm +++ b/perl-install/detect_devices.pm @@ -22,8 +22,6 @@ my %serialprobe; #-###################################################################################### #- Functions #-###################################################################################### -sub dev_is_devfs() { -e "/dev/.devfsd" } #- no $::prefix, returns false during install and that's nice :) - sub get() { #- Detect the default BIOS boot harddrive is kind of tricky. We may have IDE, @@ -41,25 +39,26 @@ sub cdroms() { grep { $_->{media_type} eq 'cdrom' } get() } sub burners() { grep { isBurner($_) } cdroms() } sub dvdroms() { grep { isDvdDrive($_) } cdroms() } sub raw_zips() { grep { member($_->{media_type}, 'fd', 'hd') && isZipDrive($_) } get() } -#-sub jazzs { grep { member($_->{media_type}, 'fd', 'hd') && isJazzDrive($_) } get() } sub ls120s() { grep { member($_->{media_type}, 'fd', 'hd') && isLS120Drive($_) } get() } sub zips() { map { $_->{device} .= 4; - $_->{devfs_device} = $_->{devfs_prefix} . '/part4'; $_; } raw_zips(); } -sub floppies() { +sub floppies { + my ($o_not_detect_legacy_floppies) = @_; require modules; my @fds; - eval { modules::load("floppy") if $::isInstall }; - if (!is_xbox()) { - @fds = map { - my $info = (!dev_is_devfs() || -e "/dev/fd$_") && c::floppy_info(devices::make("fd$_")); - if_($info && $info ne '(null)', { device => "fd$_", devfs_device => "floppy/$_", media_type => 'fd', info => $info }); - } qw(0 1); + if (!$o_not_detect_legacy_floppies) { + eval { modules::load("floppy") if $::isInstall }; + if (!is_xbox()) { + @fds = map { + my $info = c::floppy_info(devices::make("fd$_")); + if_($info && $info ne '(null)', { device => "fd$_", media_type => 'fd', info => $info }); + } qw(0 1); + } } my @ide = ls120s() and eval { modules::load("ide-floppy") }; @@ -105,35 +104,6 @@ sub get_sys_cdrom_info { } } -sub get_usb_storage_info_24 { - my (@l) = @_; - - my %usbs = map { - my $s = cat_(glob_("$_/*")); - my ($host) = $s =~ /^\s*Host scsi(\d+):/m; #-# - my ($vendor_name) = $s =~ /^\s*Vendor: (.*)/m; - my ($vendor, $id) = $s =~ /^\s*GUID: (....)(....)/m; - if_(defined $host, $host => { vendor_name => $vendor_name, usb_vendor => hex $vendor, usb_id => hex $id }); - } glob_('/proc/scsi/usb-storage-*') or return; - - #- only the entries matching the following conditions can be usb-storage devices - @l = grep { $_->{channel} == 0 && $_->{id} == 0 && $_->{lun} == 0 } @l; - my %l; push @{$l{$_->{host}}}, $_ foreach @l; - - foreach my $host (keys %usbs) { - my @choices = @{$l{$host} || []} or log::l("weird, host$host from /proc/scsi/usb-storage-*/* is not in /proc/scsi/scsi"), next; - if (@choices > 1) { - @choices = grep { $_->{info} =~ /^\Q$usbs{$host}{vendor_name}/ } @choices; - @choices or log::l("weird, can not find the good entry host$host from /proc/scsi/usb-storage-*/* in /proc/scsi/scsi"), next; - @choices == 1 or log::l("argh, can not determine the good entry host$host from /proc/scsi/usb-storage-*/* in /proc/scsi/scsi"), next; - } - add2hash($choices[0], $usbs{$host}); - } - complete_usb_storage_info(@l); - - @l; -} - sub complete_usb_storage_info { my (@l) = @_; @@ -154,20 +124,6 @@ sub complete_usb_storage_info { } } -sub get_devfs_devices { - my (@l) = @_; - - my %h = (cdrom => 'cd', hd => 'disc'); - - foreach (@l) { - $_->{devfs_prefix} = sprintf('scsi/host%d/bus%d/target%d/lun%d', $_->{host}, $_->{channel}, $_->{id}, $_->{lun}) - if $_->{bus} eq 'SCSI'; - - my $t = $h{$_->{media_type}} or next; - $_->{devfs_device} = $_->{devfs_prefix} . '/' . $t; - } -} - sub isBurner { my ($e) = @_; $e->{capacity} =~ /burner/ and return 1; @@ -185,9 +141,7 @@ sub isDvdDrive { $f && c::isDvdDrive(fileno($f)); } sub isZipDrive { $_[0]{info} =~ /ZIP\s+\d+/ } #- accept ZIP 100, untested for bigger ZIP drive. -sub isJazzDrive { $_[0]{info} =~ /\bJAZZ?\b/i } #- accept "iomega jaz 1GB" sub isLS120Drive { $_[0]{info} =~ /LS-?120|144MB/ } -sub isRemovableUsb { begins_with($_[0]{usb_media_type} || '', 'Mass Storage') && usb2removable($_[0]) } sub isKeyUsb { begins_with($_[0]{usb_media_type} || '', 'Mass Storage') && $_[0]{media_type} eq 'hd' } sub isFloppyUsb { $_[0]{usb_driver} && $_[0]{usb_driver} eq 'Removable:floppy' } sub may_be_a_hd { @@ -199,6 +153,13 @@ sub may_be_a_hd { ); } +sub get_sysfs_field_from_link { + my ($device, $field) = @_; + my $l = readlink("$device/$field"); + $l =~ s!.*/!!; + $l; +} + sub get_sysfs_usbpath_for_block { my ($device) = @_; my $host = readlink("/sys/block/$device/device"); @@ -212,55 +173,11 @@ sub get_scsi_driver { foreach (@l) { next if $_->{driver}; my $host = get_sysfs_usbpath_for_block($_->{device}); - $_->{driver} = readlink("/sys/block/$_->{device}/$host/driver"); - $_->{driver} =~ s!.*/!!; + $_->{driver} = get_sysfs_field_from_link("/sys/block/$_->{device}/$host", 'driver'); } } -sub getSCSI_24() { - my $err = sub { log::l("ERROR: unexpected line in /proc/scsi/scsi: $_[0]") }; - - my ($first, @l) = common::join_lines(cat_("/proc/scsi/scsi")) or return; - $first =~ /^Attached devices:/ or $err->($first); - - @l = map_index { - my ($host, $channel, $id, $lun) = m/^Host: scsi(\d+) Channel: (\d+) Id: (\d+) Lun: (\d+)/ or $err->($_); - my ($vendor, $model) = /^\s*Vendor:\s*(.*?)\s+Model:\s*(.*?)\s+Rev:/m or $err->($_); - my ($type) = /^\s*Type:\s*(.*)/m or $err->($_); - { info => "$vendor $model", host => $host, channel => $channel, id => $id, lun => $lun, - device => "sg$::i", raw_type => $type, bus => 'SCSI' }; - } @l; - - get_usb_storage_info_24(@l); - - each_index { - my $dev = "sd" . chr($::i + ord('a')); - put_in_hash $_, { device => $dev, media_type => isFloppyUsb($_) ? 'fd' : 'hd' }; - } grep { $_->{raw_type} =~ /Direct-Access|Optical Device/ } @l; - - each_index { - put_in_hash $_, { device => "st$::i", media_type => 'tape' }; - } grep { $_->{raw_type} =~ /Sequential-Access/ } @l; - - each_index { - put_in_hash $_, { device => "sr$::i", media_type => 'cdrom' }; - } grep { $_->{raw_type} =~ /CD-ROM|WORM/ } @l; - - # Old hp scanners report themselves as "Processor"s - # (see linux/include/scsi/scsi.h and sans-find-scanner.1) - each_index { - put_in_hash $_, { media_type => 'scanner' }; - } grep { $_->{raw_type} =~ /Scanner/ || $_->{raw_type} =~ /Processor / } @l; - - delete $_->{raw_type} foreach @l; - - get_devfs_devices(@l); - get_sys_cdrom_info(@l); - get_scsi_driver(@l); - @l; -} - -sub getSCSI_26() { +sub getSCSI() { my $dev_dir = '/sys/bus/scsi/devices'; my @scsi_types = ( @@ -276,37 +193,39 @@ sub getSCSI_26() { "Communications", ); - my @l = map { + my @l; + foreach (all($dev_dir)) { my ($host, $channel, $id, $lun) = split ':' or log::l("bad entry in $dev_dir: $_"), next; - my $dir = "$dev_dir/$_"; + + # handle both old and new kernels: + my $node = -e "$dir/block" ? "$dir/block" : top(glob_("$dir/block*")); + my ($device) = readlink($node) =~ m!/block/(.*)!; + warn("cannot get info for device ($_)"), next if !$device; + + my $usb_dir = readlink("$node/device") =~ m!/usb! && "$node/device/../../../.."; + my $get_usb = sub { chomp_(cat_("$usb_dir/$_[0]")) }; + my $get = sub { my $s = cat_("$dir/$_[0]"); $s =~ s/\s+$//; $s; }; - my $usb_dir = readlink("$dir/block/device") =~ m!/usb! && "$dir/block/device/../../../.."; - my $get_usb = sub { chomp_(cat_("$usb_dir/$_[0]")) }; - - # handle both old and new kernels: - my $node = -e "$dir/block" ? "$dir/block" : top(glob_("$dir/block*")); - my ($device) = readlink($node) =~ m!/block/(.*)!; - warn "cannot get info for device ($host, $channel, $id, $lun)" if !$device; - - my $media_type = ${{ st => 'tape', sr => 'cdrom', sd => 'hd' }}{substr($device, 0, 2)}; # Old hp scanners report themselves as "Processor"s # (see linux/include/scsi/scsi.h and sans-find-scanner.1) my $raw_type = $scsi_types[$get->('type')]; - $media_type ||= 'scanner' if $raw_type =~ /Scanner|Processor/; - { info => $get->('vendor') . ' ' . $get->('model'), host => $host, channel => $channel, id => $id, lun => $lun, + my $media_type = ${{ st => 'tape', sr => 'cdrom', sd => 'hd' }}{substr($device, 0, 2)} || + $raw_type =~ /Scanner|Processor/ && 'scanner'; + + push @l, { info => $get->('vendor') . ' ' . $get->('model'), host => $host, channel => $channel, id => $id, lun => $lun, bus => 'SCSI', media_type => $media_type, device => $device, $usb_dir ? ( usb_vendor => hex($get_usb->('idVendor')), usb_id => hex($get_usb->('idProduct')), ) : (), }; - } all($dev_dir); + } @l = sort { $a->{host} <=> $b->{host} || $a->{channel} <=> $b->{channel} || $a->{id} <=> $b->{id} || $a->{lun} <=> $b->{lun} } @l; @@ -316,12 +235,10 @@ sub getSCSI_26() { $_->{media_type} = 'fd' if $_->{media_type} eq 'hd' && isFloppyUsb($_); } - get_devfs_devices(@l); get_sys_cdrom_info(@l); get_scsi_driver(@l); @l; } -sub getSCSI() { c::kernel_version() =~ /^\Q2.6/ ? getSCSI_26() : getSCSI_24() } my %eide_hds = ( @@ -373,14 +290,11 @@ sub getIDE() { my $host = $num; ($host, my $id) = divide($host, 2); ($host, my $channel) = divide($host, 2); - my $devfs_prefix = sprintf('ide/host%d/bus%d/target%d/lun0', $host, $channel, $id); push @idi, { media_type => $type, device => basename($d), - devfs_prefix => $devfs_prefix, info => $info, host => $host, channel => $channel, id => $id, bus => 'ide', if_($vendor, Vendor => $vendor), if_($model, Model => $model) }; } - get_devfs_devices(@idi); get_sys_cdrom_info(@idi); @idi; } @@ -401,6 +315,10 @@ sub getCompaqSmartArray() { my ($name) = m|/(.*)|; for (my $i = 0; -r ($f = "${prefix}$i"); $i++) { my @raw_devices = cat_($f) =~ m|^\s*($name/.*?):|gm; + + #- this is ugly and buggy. keeping it for 2007.0 + #- on a cciss, cciss/cciss0 didn't contain c0d0, but cciss/cciss1 did contain c0d1 + #- the line below adds both c0d0 and c0d1 for cciss0, and so some duplicates @raw_devices or @raw_devices = grep { m!^$name/! } block_devices(); foreach my $raw_device (@raw_devices) { @@ -411,7 +329,8 @@ sub getCompaqSmartArray() { } } } - @idi; + #- workaround the buggy code above. this should be safe though + uniq_ { $_->{device} } @idi; } sub getDAC960() { @@ -464,37 +383,128 @@ sub ix86_cpu_frequency() { cat_('/proc/cpuinfo') =~ /cpu MHz\s*:\s*(\d+)/ && $1; } +sub probe_category { + my ($category) = @_; + + require list_modules; + my @modules = list_modules::category2modules($category); + + if_($category =~ /sound/ && arch() =~ /ppc/ && get_mac_model() !~ /IBM/, + { driver => 'snd-powermac', description => 'Macintosh built-in' }, + ), + grep { + if ($category eq 'network/isdn') { + my $b = $_->{driver} =~ /ISDN:([^,]*),?([^,]*)(?:,firmware=(.*))?/; + if ($b) { + $_->{driver} = $1; + $_->{type} = $2; + $_->{type} =~ s/type=//; + $_->{firmware} = $3; + $_->{driver} eq "hisax" and $_->{options} .= " id=HiSax"; + } + $b; + } else { + member($_->{driver}, @modules); + } + } probeall(); +} + sub getSoundDevices() { - modules::probe_category('multimedia/sound'); + probe_category('multimedia/sound'); } sub isTVcardConfigurable { member($_[0]{driver}, qw(bttv cx88 saa7134)) } -sub getTVcards() { modules::probe_category('multimedia/tv') } +sub getTVcards() { probe_category('multimedia/tv') } sub getInputDevices() { my (@devices, $device); foreach (cat_('/proc/bus/input/devices')) { if (/^I:/) { - push @devices, $device if $device; $device = {}; - $device->{vendor} = $1 if /Vendor=([0-9a-f]+)/; - $device->{id} = $1 if /Product=([0-9a-f]+)/; - } - $device->{description} = "|$1" if /N: Name="(.*)"/; - $device->{driver} = $1 if /H: Handlers=(\w+)/; - if (/P: Phys=(.*)/) { + $device->{vendor} = /Vendor=(\w+)/ && $1; + $device->{id} = /Product=(\w+)/ && $1; + } elsif (/N: Name="(.*)"/) { + my $descr = $1; + $device->{description} = "|$descr"; + + #- I: Bus=0011 Vendor=0002 Product=0008 Version=7321 + #- N: Name="AlpsPS/2 ALPS GlidePoint" + #- P: Phys=isa0060/serio1/input0 + #- H: Handlers=mouse1 event2 ts1 + #- B: EV=f + #- B: KEY=420 0 70000 0 0 0 0 0 0 0 0 #=> BTN_LEFT BTN_RIGHT BTN_MIDDLE BTN_TOOL_FINGER BTN_TOUCH + #- or B: KEY=420 0 670000 0 0 0 0 0 0 0 0 #=> same with BTN_BACK + #- B: REL=3 #=> X Y + #- B: ABS=1000003 #=> X Y PRESSURE + + #- I: Bus=0011 Vendor=0002 Product=0008 Version=2222 + #- N: Name="AlpsPS/2 ALPS DualPoint TouchPad" + #- P: Phys=isa0060/serio1/input0 + #- S: Sysfs=/class/input/input2 + #- H: Handlers=mouse1 ts1 event2 + #- B: EV=f + #- B: KEY=420 0 70000 0 0 0 0 0 0 0 0 + #- B: REL=3 + #- B: ABS=1000003 + + #- I: Bus=0011 Vendor=0002 Product=0007 Version=0000 + #- N: Name="SynPS/2 Synaptics TouchPad" + #- P: Phys=isa0060/serio1/input0 + #- S: Sysfs=/class/input/input1 + #- H: Handlers=mouse0 event1 ts0 + #- B: EV=b + #- B: KEY=6420 0 70000 0 0 0 0 0 0 0 0 #=> BTN_LEFT BTN_RIGHT BTN_MIDDLE BTN_TOOL_FINGER BTN_TOUCH BTN_TOOL_TRIPLETAP + #- or B: KEY=6420 0 670000 0 0 0 0 0 0 0 0 #=> same with BTN_BACK + #- or B: KEY=420 30000 670000 0 0 0 0 0 0 0 0 #=> same without BTN_TOOL_TRIPLETAP but with BTN_B + #- B: ABS=11000003 #=> X Y PRESSURE TOOL_WIDTH + + $device->{Synaptics} = $descr eq 'SynPS/2 Synaptics TouchPad'; + $device->{ALPS} = $descr =~ m!^AlpsPS/2 ALPS!; + + } elsif (/H: Handlers=(\w+)/) { + $device->{driver} = $1; + } elsif (/P: Phys=(.*)/) { $device->{location} = $1; $device->{bus} = 'isa' if $device->{location} =~ /^isa/; $device->{bus} = 'usb' if $device->{location} =~ /^usb/i; - } + } elsif (/B: REL=(.* )?(.*)/) { + #- REL=3 #=> X Y + #- REL=103 #=> X Y WHEEL + #- REL=143 #=> X Y HWHEEL WHEEL + #- REL=1c3 #=> X Y HWHEEL DIAL WHEEL + my $REL = hex($2); + $device->{HWHEEL} = 1 if $REL & (1 << 6); + $device->{WHEEL} = 1 if $REL & (1 << 8); #- not reliable ("Mitsumi Apple USB Mouse" says REL=103 and KEY=1f0000 ...) + + } elsif (/B: KEY=(\S+)/) { + #- some KEY explained: + #- (but note that BTN_MIDDLE can be reported even if missing) + #- (and "Mitsumi Apple USB Mouse" reports 1f0000) + #- KEY=30000 0 0 0 0 0 0 0 0 #=> BTN_LEFT BTN_RIGHT + #- KEY=70000 0 0 0 0 0 0 0 0 #=> BTN_LEFT BTN_RIGHT BTN_MIDDLE + #- KEY=1f0000 0 0 0 0 0 0 0 0 #=> BTN_LEFT BTN_RIGHT BTN_MIDDLE BTN_SIDE BTN_EXTRA + my $KEY = hex($1); + $device->{SIDE} = 1 if $KEY & (1 << 0x13); + + } elsif (/^\s*$/) { + push @devices, $device if $device; + undef $device; + } } - push @devices, $device if $device; @devices; } -sub getSynapticsTouchpads() { - grep { $_->{description} =~ m,^\|(?:SynPS/2 Synaptics TouchPad$|AlpsPS/2 ALPS), } getInputDevices(); +sub getInputDevices_and_usb() { + my @l = getInputDevices(); + + foreach my $usb (usb_probe()) { + if (my $e = find { hex($_->{vendor}) == $usb->{vendor} && hex($_->{id}) == $usb->{id} } @l) { + $e->{usb} = $usb; + } + } + + @l; } sub getSerialModem { @@ -518,27 +528,25 @@ sub getSerialModem { foreach my $modem (@modems) { #- add an alias for macserial on PPC $modules_conf->set_alias('serial', $serdev) if arch() =~ /ppc/ && $modem->{device}; - foreach (@devs) { $_->{type} =~ /serial/ and $modem->{device} = $_->{device} } + foreach (@devs) { $_->{device} and $modem->{device} = $_->{device} } } @modems; } sub getModem { my ($modules_conf) = @_; - getSerialModem($modules_conf, {}), matching_driver__regexp('www\.linmodems\.org'), - matching_driver(list_modules::category2modules('network/modem'), list_modules::category2modules('network/slmodem')); + getSerialModem($modules_conf, {}), get_winmodems(); } -sub getSpeedtouch() { - grep { $_->{description} eq 'Alcatel|USB ADSL Modem (Speed Touch)' } probeall(); +sub get_winmodems() { + matching_driver__regexp('www\.linmodems\.org'), + matching_driver(list_modules::category2modules('network/modem'), + list_modules::category2modules('network/slmodem')); } sub getBewan() { matching_desc__regexp('Bewan Systems\|.*ADSL|BEWAN ADSL USB|\[Unicorn\]'); } -sub getSagem() { - matching_driver(qw(eagle-usb ueagle-atm)); -} # generate from the following from eci driver sources: # perl -e 'while (<>) { print qq("$1$2",\n"$3$4",\n) if /\b([a-z\d]*)\s*([a-z\d]*)\s*([a-z\d]*)\s*([a-z\d]*)$/ }' <modems.db|sort|uniq @@ -572,27 +580,34 @@ sub getECI() { grep { member(sprintf("%04x%04x%04x%04x", $_->{vendor}, $_->{id}, $_->{subvendor}, $_->{subid}), @ids) } usb_probe(); } +sub get_xdsl_usb_devices() { + my @bewan = detect_devices::getBewan(); + $_->{driver} = $_->{bus} eq 'USB' ? 'unicorn_usb_atm' : 'unicorn_pci_atm' foreach @bewan; + my @eci = detect_devices::getECI(); + $_->{driver} = 'eciusb' foreach @eci; + my @usb = detect_devices::probe_category('network/usb_dsl'); + $_->{description} = "USB ADSL modem (eagle chipset)" foreach + grep { $_->{driver} eq 'ueagle-atm' && $_->{description} eq '(null)' } @usb; + @usb, @bewan, @eci; +} + sub is_lan_interface { - # we want LAN like interfaces here (eg: ath|br|eth|fddi|plip|ra|tr|usb|wifi|wlan). + # we want LAN like interfaces here (eg: ath|br|eth|fddi|plip|ra|tr|usb|wlan). # there's also bnep%d for bluetooth, bcp%d... # we do this by blacklisting the following interfaces: # - ippp|isdn|plip|ppp (initscripts suggest that isdn%d can be created but kernel sources claim not) # ippp%d are created by drivers/isdn/i4l/isdn_ppp.c # plip%d are created by drivers/net/plip.c # ppp%d are created by drivers/net/ppp_generic.c - # - # we need both detection schemes since: - # - get_netdevices() use the SIOCGIFCONF ioctl that does not list interfaces that are down - # - /proc/net/dev does not list VLAN and IP aliased interfaces - is_useful_interface($_[0]) && - $_[0] !~ /^(?:lo|ippp|isdn|plip|ppp|sit0|wifi)/; + $_[0] !~ /^(?:ippp|isdn|plip|ppp)/; } sub is_useful_interface { # - sit0 which is *always* created by net/ipv6/sit.c, thus is always created since net.agent loads ipv6 module # - wifi%d are created by 3rdparty/hostap/hostap_hw.c (pseudo statistics devices, #14523) - $_[0] !~ /^(?:lo|sit0|wifi)/; + # ax*, rose*, nr*, bce* and scc* are Hamradio devices (#28776) + $_[0] !~ /^(?:lo|sit0|wifi|ax|rose|nr|bce|scc)/; } sub is_wireless_interface { @@ -604,34 +619,64 @@ sub is_wireless_interface { #- i.e interfaces for which get_wireless_stats() is available c::isNetDeviceWirelessAware($interface) || -e "/sys/class/net/$interface/wireless"; } -sub get_wireless_interface() { find { is_wireless_interface($_) } getNet() } + +sub get_all_net_devices() { + # we need both detection schemes since: + # - get_netdevices() use the SIOCGIFCONF ioctl that does not list interfaces that are down + # - /proc/net/dev does not list VLAN and IP aliased interfaces + uniq( + (map { if_(/^\s*([A-Za-z0-9:\.]*):/, $1) } cat_("/proc/net/dev")), + c::get_netdevices(), + ); +} + +sub get_lan_interfaces() { grep { is_lan_interface($_) } get_all_net_devices() } +sub get_net_interfaces() { grep { is_useful_interface($_) } get_all_net_devices() } +sub get_wireless_interface() { find { is_wireless_interface($_) } get_lan_interfaces() } sub is_bridge_interface { my ($interface) = @_; -f "/sys/class/net/$interface/bridge/bridge_id"; } -sub get_sysfs_device_id_map { +sub get_ids_from_sysfs_device { my ($dev_path) = @_; - my $is_usb = -f "$dev_path/bInterfaceNumber"; - $is_usb ? - { id => '../idProduct', vendor => '../idVendor' } : - { id => "device", subid => "subsystem_device", vendor => "vendor", subvendor => "subsystem_vendor" }; + my $dev_cat = sub { chomp_(cat_("$dev_path/$_[0]")) }; + my $usb_root = -f "$dev_path/bInterfaceNumber" && "../" || -f "$dev_path/idVendor" && ""; + my $is_pcmcia = -f "$dev_path/card_id"; + my $sysfs_ids; + my $bus = get_sysfs_field_from_link($dev_path, "bus"); + #- FIXME: use $bus + if ($is_pcmcia) { + $sysfs_ids = { modalias => $dev_cat->('modalias') }; + } else { + $sysfs_ids = $bus eq 'ieee1394' ? + { + version => "../vendor_id", + specifier_id => "specifier_id", + specifier_version => "version", + } : + defined $usb_root ? + { id => $usb_root . 'idProduct', vendor => $usb_root . 'idVendor' } : + { id => "device", subid => "subsystem_device", vendor => "vendor", subvendor => "subsystem_vendor" }; + $_ = hex($dev_cat->($_)) foreach values %$sysfs_ids; + if ($bus eq 'pci') { + my $device = basename(readlink $dev_path); + my @ids = $device =~ /^(.{4}):(.{2}):(.{2})\.(.+)$/; + @{%$sysfs_ids}{qw(pci_domain pci_bus pci_device pci_function)} = map { hex($_) } @ids if @ids; + } + } + $sysfs_ids; } -sub get_all_net_devices() { - uniq( - (map { if_(/^\s*([A-Za-z0-9:\.]*):/, $1) } cat_("/proc/net/dev")), - c::get_netdevices(), - ); +sub device_matches_sysfs_ids { + my ($device, $sysfs_ids) = @_; + every { defined $device->{$_} && member($device->{$_}, $sysfs_ids->{$_}, 0xffff) } keys %$sysfs_ids; } -sub getNet() { - grep { is_lan_interface($_) } get_all_net_devices(); - } - -sub get_net_interfaces() { - grep { is_useful_interface($_) } get_all_net_devices(); +sub device_matches_sysfs_device { + my ($device, $dev_path) = @_; + device_matches_sysfs_ids($device, get_ids_from_sysfs_device($dev_path)); } #sub getISDN() { @@ -658,7 +703,7 @@ sub getUPS() { $_->{media_type} = 'UPS'; $_->{driver} = 'newhidups'; $_; - } grep { $_->{driver} =~ /ups$/ && $_->{description} !~ /American Power Conversion\|Back-UPS|Keyboard|Logitech|WingMan/ } @usb_devices); + } grep { $_->{driver} =~ /ups$/ && $_->{description} !~ /American Power Conversion\|Back-UPS|Chicony|Keyboard|Logitech|SAITEK|WingMan/ } @usb_devices); } $pcitable_addons = <<'EOF'; @@ -705,9 +750,10 @@ my (@pci, @usb); sub pci_probe__real() { add_addons($pcitable_addons, map { my %l; - @l{qw(vendor id subvendor subid pci_bus pci_device pci_function media_type driver description)} = split "\t"; + @l{qw(vendor id subvendor subid pci_domain pci_bus pci_device pci_function media_type nice_media_type driver description)} = split "\t"; $l{$_} = hex $l{$_} foreach qw(vendor id subvendor subid); $l{bus} = 'PCI'; + $l{sysfs_device} = sprintf('/sys/bus/pci/devices/%04x:%02x:%02x.%d', $l{pci_domain}, $l{pci_bus}, $l{pci_device}, $l{pci_function}); \%l; } c::pci_probe()); } @@ -727,6 +773,7 @@ sub usb_probe__real() { @l{qw(vendor id media_type driver description pci_bus pci_device)} = split "\t"; $l{media_type} = join('|', grep { $_ ne '(null)' } split('\|', $l{media_type})); $l{$_} = hex $l{$_} foreach qw(vendor id); + $l{sysfs_device} = "/sys/class/usb_device/usbdev$l{pci_bus}.$l{pci_device}/device"; $l{bus} = 'USB'; \%l; } c::usb_probe()); @@ -778,37 +825,45 @@ sub firewire_probe() { } sub pcmcia_controller_probe() { - require list_modules; - my @modules = list_modules::category2modules('bus/pcmcia'); - grep { member($_->{driver}, @modules) } probeall(); -} - -sub real_pcmcia_probe() { - return if $::testing; - - c::pcmcia_probe() || first(map { $_->{driver} } pcmcia_controller_probe()); + my ($controller) = probe_category('bus/pcmcia'); + if (!$controller && !$::testing && !$::noauto && arch() =~ /i.86/) { + my $driver = c::pcmcia_probe(); + $controller = { driver => $driver, description => "PCMCIA controller ($driver)" } if $driver; + } + $controller; } sub pcmcia_probe() { - -e '/var/run/stab' || -e '/var/lib/pcmcia/stab' or return (); - - my (@devs, $desc); - foreach (cat_('/var/run/stab'), cat_('/var/lib/pcmcia/stab')) { - if (/^Socket\s+\d+:\s+(.*)/) { - $desc = $1; - } else { - my (undef, $type, $module, undef, $device) = split; - push @devs, { description => $desc, driver => $module, type => $type, device => $device }; - } - } - @devs; + require modalias; + require modules; + my $dev_dir = '/sys/bus/pcmcia/devices'; + map { + my $dir = "$dev_dir/$_"; + my $get = sub { chomp_(cat_("$dir/$_[0]")) }; + my $class_dev = first(glob_("$dir/tty*")); + my $device = $class_dev && get_sysfs_field_from_link($dir, basename($class_dev)); + my $modalias = $get->('modalias'); + my $driver = get_sysfs_field_from_link($dir, 'driver'); + #- fallback on modalias result + #- but only if the module isn't loaded yet (else, it would already be binded) + #- this prevents from guessing the wrong driver for multi-function devices + my $module = $modalias && first(modalias::get_modules($modalias)); + $driver ||= !member($module, modules::loaded_modules()) && $module; + { + description => join(' ', grep { $_ } map { $get->("prod_id$_") } 1 .. 4), + driver => $driver, + if_($modalias, modalias => $modalias), + if_($device, device => $device), + bus => 'PCMCIA', + }; + } all($dev_dir); } my $dmi_probe; sub dmi_probe() { $dmi_probe ||= [ map { /(.*?)\t(.*)/ && { bus => 'DMI', driver => $1, description => $2 }; - } c::dmi_probe() ]; + } $> ? () : c::dmi_probe() ]; @$dmi_probe; } @@ -819,6 +874,10 @@ sub probeall() { pci_probe(), usb_probe(), firewire_probe(), pcmcia_probe(), dmi_probe(); } +sub probeall__real() { + return if $::noauto; + pci_probe__real(), usb_probe__real(), firewire_probe(), pcmcia_probe(), dmi_probe(); +} sub matching_desc__regexp { my ($regexp) = @_; grep { $_->{description} =~ /$regexp/i } probeall(); @@ -845,13 +904,16 @@ sub probe_unique_name { $l[0]; } -sub stringlist() { +sub stringlist { + my ($b_verbose) = @_; map { + my $ids = $b_verbose || $_->{description} eq '(null)' ? sprintf("vendor:%04x device:%04x", $_->{vendor}, $_->{id}) : ''; + my $subids = $_->{subid} && $_->{subid} != 0xffff ? sprintf("subv:%04x subd:%04x", $_->{subvendor}, $_->{subid}) : ''; sprintf("%-16s: %s%s%s", $_->{driver} || 'unknown', - $_->{description} eq '(null)' ? sprintf("Vendor=0x%04x Device=0x%04x", $_->{vendor}, $_->{id}) : $_->{description}, + $_->{description}, $_->{media_type} ? sprintf(" [%s]", $_->{media_type}) : '', - $_->{subid} && $_->{subid} != 0xffff ? sprintf(" SubVendor=0x%04x SubDevice=0x%04x", $_->{subvendor}, $_->{subid}) : '', + $ids || $subids ? " ($ids" . ($ids && $subids && " ") . "$subids)" : '', ); } probeall(); } @@ -899,6 +961,7 @@ my (@dmis, $dmidecode_already_runned); sub dmidecode() { return @dmis if $dmidecode_already_runned; + return if $>; my ($ver, @l) = run_program::get_stdout('dmidecode'); my $tab = "\t"; @@ -906,7 +969,7 @@ sub dmidecode() { #- new dmidecode output is less indented $tab = ''; #- drop header - shift @l while $l[0] ne "\n"; + shift @l while @l && $l[0] ne "\n"; } foreach (@l) { @@ -960,7 +1023,10 @@ sub isLaptop() { matching_desc__regexp('Neomagic.*Magic(Media|Graph)') || matching_desc__regexp('ViRGE.MX') || matching_desc__regexp('S3.*Savage.*[IM]X') || matching_desc__regexp('ATI.*(Mobility|LT)')) - || cat_('/proc/cpuinfo') =~ /\bmobile\b/i; + || cat_('/proc/cpuinfo') =~ /\bmobile\b/i + || probe_unique_name("Type") eq 'laptop' + #- ipw2100/2200/3945 are Mini-PCI (Express) adapters + || (any { member($_->{driver}, qw(ipw2100 ipw2200 ipw3945)) } pci_probe()); } sub BIGMEM() { @@ -974,7 +1040,7 @@ sub is_i586() { } sub is_xbox() { - any { $_->{vendor} == 0x10de && $_->{id} == 0x02a5 } detect_devices::pci_probe(); + any { $_->{vendor} == 0x10de && $_->{id} == 0x02a5 } pci_probe(); } sub has_cpu_flag { @@ -982,17 +1048,14 @@ sub has_cpu_flag { cat_('/proc/cpuinfo') =~ /^flags.*\b$flag\b/m; } -sub matching_type { - my ($type) = @_; - if ($type =~ /laptop/i) { - return isLaptop(); - } elsif ($type =~ /wireless/i) { - return to_bool(get_wireless_interface()); - } +sub matching_types() { + +{ + laptop => isLaptop(), + '64bit' => to_bool(arch() =~ /64/), + wireless => to_bool(get_wireless_interface() || probe_category('network/wireless')), + }; } -sub usbMice() { grep { $_->{media_type} =~ /\|Mouse/ && $_->{driver} !~ /wacom/ || - $_->{driver} =~ /Mouse:USB/ } usb_probe() } sub usbWacom() { grep { $_->{driver} =~ /wacom/ } usb_probe() } sub usbKeyboards() { grep { $_->{media_type} =~ /\|Keyboard/ } usb_probe() } sub usbStorage() { grep { $_->{media_type} =~ /Mass Storage\|/ } usb_probe() } |