summaryrefslogtreecommitdiffstats
path: root/perl-install/detect_devices.pm
diff options
context:
space:
mode:
Diffstat (limited to 'perl-install/detect_devices.pm')
-rw-r--r--perl-install/detect_devices.pm368
1 files changed, 365 insertions, 3 deletions
diff --git a/perl-install/detect_devices.pm b/perl-install/detect_devices.pm
index f9fe0d392..2e1a7c4d1 100644
--- a/perl-install/detect_devices.pm
+++ b/perl-install/detect_devices.pm
@@ -16,6 +16,39 @@ use modules;
use c;
use feature 'state';
+
+=head2 SYNOPSYS
+
+The B<detect_devices> modules offers a high level API for detecting devices.*
+It mostly relies on the L<c> modules for gluing libldetect back into the Perl world, and thus
+being able to enumerate DMI/HID/PCI/USB devices.
+
+Other devices are mostly detected through /proc & /sys.
+
+Then the L<list_modules> enables to map modules into categories such as:
+
+=over
+
+=item network/ethernet,
+
+=item network/wireless,
+
+=item network/wifi,
+
+=item disk/sata,
+
+=item disk/scsi,
+
+=item ...
+
+=back
+
+This enables to detect a category by mapping drivers to categories.
+
+=head2 Listing block devices
+
+=cut
+
#-#####################################################################################
#- Globals
#-#####################################################################################
@@ -25,6 +58,14 @@ my %serialprobe;
#- Functions
#-######################################################################################
+=over
+
+=item get()
+
+Returns a list of all block devices (IDE, SCSI, SATA, virtual, RAID, ...)
+
+=cut
+
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
@@ -190,6 +231,12 @@ sub get_scsi_driver {
}
}
+=item getSCSI()
+
+Returns a list of all SCSI device.
+
+=cut
+
sub getSCSI() {
my $dev_dir = '/sys/bus/scsi/devices';
@@ -303,6 +350,11 @@ sub _get_hd_vendor {
return ("Hitachi", $info) if $info =~ /^HD[ST][0-9]/;
}
+=item getIDE()
+
+Returns a list of all IDE device.
+
+=cut
sub getIDE() {
my @idi;
@@ -337,6 +389,7 @@ sub block_devices() {
: map { $_->{dev} } do { require fs::proc_partitions; fs::proc_partitions::read_raw() };
}
+#Returns a list of all CCISS devices (Compaq Smart Array).
sub getCompaqSmartArray() {
my (@idi, $f);
@@ -385,6 +438,12 @@ sub getATARAID() {
values %l;
}
+=item getXenBlk()
+
+Returns a list of all Xen block devices (/dev/xvd*).
+
+=cut
+
sub getXenBlk() {
-d '/sys/bus/xen/devices' or return;
map {
@@ -393,6 +452,12 @@ sub getXenBlk() {
} glob("/sys/block/xvd*");
}
+=item getVirtIO()
+
+Returns a list of all VirtIO block devices (/dev/vd*).
+
+=cut
+
sub getVirtIO() {
-d '/sys/bus/virtio/devices' or return;
map {
@@ -418,6 +483,12 @@ sub getMmcBlk() {
# cpu_freq = arch() =~ /^alpha/ ? "cycle frequency [Hz]" :
# arch() =~ /^ppc/ ? "clock" : "cpu MHz"
+=item getCPUs()
+
+Returns a list of all CPUs.
+
+=cut
+
sub getCPUs() {
my (@cpus, $cpu);
foreach (cat_("/proc/cpuinfo")) {
@@ -436,6 +507,14 @@ sub ix86_cpu_frequency() {
cat_('/proc/cpuinfo') =~ /cpu MHz\s*:\s*(\d+)/ && $1;
}
+=item probe_category($category)
+
+Returns a list of devices which drivers are in the asked category.
+
+eg: my @eth_cards = probe_category('network/ethernet');
+
+=cut
+
sub probe_category {
my ($category) = @_;
@@ -601,6 +680,14 @@ sub serialPort2text {
$_[0] =~ /ttyS(\d+)/ ? "$_[0] / COM" . ($1 + 1) : $_[0];
}
+=back
+
+=head2 Network
+
+=over
+
+=cut
+
sub getSerialModem {
my ($modules_conf, $o_mouse) = @_;
my $mouse = $o_mouse || {};
@@ -628,6 +715,11 @@ sub getSerialModem {
@modems;
}
+=item getModem()
+
+Return list of modems (serial, WinModems)
+=cut
+
our $detect_serial_modem = 1;
sub getModem {
my ($modules_conf) = @_;
@@ -676,6 +768,12 @@ sub getECI() {
grep { member(sprintf("%04x%04x%04x%04x", $_->{vendor}, $_->{id}, $_->{subvendor}, $_->{subid}), @ids) } usb_probe();
}
+=item get_xdsl_usb_devices()
+
+Return list of xDSL devices.
+
+=cut
+
sub get_xdsl_usb_devices() {
my @bewan = detect_devices::getBewan();
$_->{driver} = $_->{bus} eq 'USB' ? 'unicorn_usb_atm' : 'unicorn_pci_atm' foreach @bewan;
@@ -687,6 +785,12 @@ sub get_xdsl_usb_devices() {
@usb, @bewan, @eci;
}
+=item is_lan_interface($device)
+
+Is it a LAN interface (blacklist some interfaces (PPP, ...)?
+
+=cut
+
sub is_lan_interface {
#- 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...
@@ -701,6 +805,12 @@ sub is_lan_interface {
$_[0] !~ /^(?:hso|ippp|isdn|plip|ppp|pan)/;
}
+=item is_useful_interface($device)
+
+Is it a usefull interface (blacklist some interfaces (loopback, sit, wifi, ...)?
+
+=cut
+
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)
@@ -709,6 +819,12 @@ sub is_useful_interface {
$_[0] !~ /^(?:lo|sit0|wifi|wmaster|ax|rose|nr|bce|scc)/;
}
+=item is_wireless_interface($device)
+
+Is it a WiFi interface?
+
+=cut
+
sub is_wireless_interface {
my ($interface) = @_;
#- some wireless drivers don't always support the SIOCGIWNAME ioctl
@@ -721,6 +837,12 @@ sub is_wireless_interface {
|| -e "/sys/class/net/$interface/phy80211";
}
+=item get_all_net_devices()
+
+Returns list of all network devices
+
+=cut
+
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
@@ -731,15 +853,49 @@ sub get_all_net_devices() {
);
}
+=item get_lan_interfaces()
+
+Returns list of all LAN devices
+
+=cut
+
sub get_lan_interfaces() { grep { is_lan_interface($_) } get_all_net_devices() }
+
+=item get_net_interfaces()
+
+Returns list of all usefull network devices
+
+=cut
+
sub get_net_interfaces() { grep { is_useful_interface($_) } get_all_net_devices() }
+
+=item get_wireless_interface()
+
+Returns list of all Wireless devices
+
+=cut
+
sub get_wireless_interface() { find { is_wireless_interface($_) } get_lan_interfaces() }
+=item is_bridge_interface($interface)
+
+Is it a bridge?
+
+=cut
+
sub is_bridge_interface {
my ($interface) = @_;
-f "/sys/class/net/$interface/bridge/bridge_id";
}
+=back
+
+=head2 Enumerating devices
+
+=over
+
+=cut
+
sub get_ids_from_sysfs_device {
my ($dev_path) = @_;
my $dev_cat = sub { chomp_(cat_("$dev_path/$_[0]")) };
@@ -867,6 +1023,13 @@ sub pci_probe__real() {
$l;
} c::pci_probe());
}
+
+=item pci_probe()
+
+Cache the result of c::pci_probe() and return the list of items in the PCI devices.
+
+=cut
+
sub pci_probe() {
state $done;
if (!$done) {
@@ -889,6 +1052,13 @@ sub usb_probe__real() {
$l;
} c::usb_probe());
}
+
+=item usb_probe()
+
+Cache the result of c::usb_probe() and return the list of items in the USB devices.
+
+=cut
+
sub usb_probe() {
if ($::isStandalone && @usb) {
@usb;
@@ -897,6 +1067,12 @@ sub usb_probe() {
}
}
+=item firewire_probe()
+
+Return list of Firewire controllers
+
+=cut
+
sub firewire_probe() {
my $dev_dir = '/sys/bus/ieee1394/devices';
my @l = map {
@@ -936,6 +1112,12 @@ sub firewire_probe() {
@l;
}
+=item pcmcia_controller_probe()
+
+Return list of PCMCIA controllers
+
+=cut
+
sub pcmcia_controller_probe() {
my ($controller) = probe_category('bus/pcmcia');
if (!$controller && !$::testing && !$::noauto && arch() =~ /i.86/) {
@@ -945,6 +1127,12 @@ sub pcmcia_controller_probe() {
$controller;
}
+=item pcmcia_probe()
+
+Return list of PCMCIA devices (eg: ethernet PCMCIA cards, ...)
+
+=cut
+
sub pcmcia_probe() {
require modalias;
require modules;
@@ -972,6 +1160,12 @@ sub pcmcia_probe() {
} all($dev_dir);
}
+=item dmi_probe()
+
+Cache the result of c::dmi_probe() (aka dmidecode) and return the list of items in the DMI table
+
+=cut
+
sub dmi_probe() {
state $dmi_probe;
if (arch() !~ /86/) {
@@ -981,7 +1175,15 @@ sub dmi_probe() {
@$dmi_probe;
}
+=item probeall()
+
+Returns a list of all PCI/USB/Firewire/PCMCIA/DMI/HID devices.
+It's usually called through a higher level filtering function.
+
+=cut
+
# pcmcia_probe provides field "device", used in network.pm
+# => probeall with $probe_type is unsafe
sub probeall() {
return if $::noauto;
@@ -1071,6 +1273,11 @@ sub hasPCMCIA() { $::o->{pcmcia} }
my (@dmis, $dmidecode_already_runned);
+=item dmidecode()
+
+Return list of DMI categories from DMI table
+
+=cut
# we return a list b/c several DMIs have the same name:
sub dmidecode() {
return @dmis if $dmidecode_already_runned;
@@ -1103,13 +1310,25 @@ sub dmidecode() {
$dmidecode_already_runned = 1;
@dmis;
}
+
+=item dmi_detect_memory($category)
+
+Return only one category from DMI table
+
+=cut
+
sub dmidecode_category {
my ($cat) = @_;
my @l = grep { $_->{name} eq $cat } dmidecode();
wantarray() ? @l : $l[0] || {};
}
-#- size in MB
+=item dmi_detect_memory()
+
+Return RAM size in MB according to DMI table
+
+=cut
+
sub dmi_detect_memory() {
my @l1 = map { $_->{'Enabled Size'} =~ /(\d+) MB/ && $1 } dmidecode_category('Memory Module');
my @l2 = map { $_->{'Form Factor'} =~ /^(SIMM|SIP|DIP|DIMM|FB-DIMM|RIMM|SODIMM|SRIMM)$/ &&
@@ -1118,6 +1337,18 @@ sub dmi_detect_memory() {
max(sum(@l1), sum(@l2));
}
+=back
+
+=head2 Test helpers
+
+=over
+
+=item computer_info()
+
+Analyze "Chassis" & "Bios" in dmidecode output and return a hash of flags/values (isLaptop, isServer, BIOS_Year)
+
+=cut
+
sub computer_info() {
my $Chassis = dmidecode_category('Chassis')->{Type} =~ /(\S+)/ && $1;
@@ -1132,8 +1363,44 @@ sub computer_info() {
};
}
-#- try to detect a laptop, we assume pcmcia service is an indication of a laptop or
-#- the following regexp to match graphics card apparently only used for such systems.
+=item isLaptop()
+
+try to detect a laptop. We assume the following is an indication of a laptop:
+
+=over 4
+
+=item *
+
+pcmcia service
+
+=item *
+
+computer_info() (really dmidecode) telling us it's a laptop
+
+=item *
+
+ACPI lid button
+
+=item *
+
+a regexp to match graphics card apparently only used for such systems.
+
+=item *
+
+Mobility CPU
+
+=item *
+
+having Type as Laptop in some device
+
+=item *
+
+Intel ipw2100/2200/3945 Wireless
+
+=back
+
+=cut
+
sub isLaptop() {
arch() =~ /ppc/ ?
get_mac_model() =~ /Book/ :
@@ -1150,6 +1417,12 @@ sub isLaptop() {
|| (any { member($_->{driver}, qw(ipw2100 ipw2200 ipw3945)) } pci_probe());
}
+=item isServer()
+
+Is it a server?
+
+=cut
+
sub isServer() {
computer_info()->{isServer}
|| (any { $_->{Type} =~ /ECC/ } dmidecode_category('Memory Module'))
@@ -1161,6 +1434,12 @@ sub isServer() {
|| (any { $_->{'model name'} =~ /(Xeon|Opteron)/i } getCPUs());
}
+=item isHyperv()
+
+Are we running under Hyper-V hypervisor?
+
+=cut
+
sub isHyperv() {
dmidecode_category('System')->{Manufacturer} =~ /Microsoft Corporation/i
&& dmidecode_category('System')->{'Product Name'} =~ /Virtual Machine/i;
@@ -1210,33 +1489,75 @@ sub is_xbox() {
any { $_->{vendor} == 0x10de && $_->{id} == 0x02a5 } pci_probe();
}
+=item is_virtualbox()
+
+Are we running under VirtualBox hypervisor?
+
+=cut
+
sub is_virtualbox() {
any { $_->{driver} eq 'vboxadd' } detect_devices::pci_probe();
}
+=item is_vmware()
+
+Are we running under VMware hypervisor?
+
+=cut
+
sub is_vmware() {
any { $_->{driver} =~ /Card:VMware/ } detect_devices::pci_probe();
}
+=item is_netbook_nettop()
+
+Is it a NetBook?
+
+=cut
+
sub is_netbook_nettop() {
my @cpus = getCPUs();
(any { $_->{'model name'} =~ /(\bIntel\(R\) Atom\(TM\)\B)/i } @cpus) ||
(any { $_->{'model name'} =~ /(\bIntel\(R\) Celeron\(R\) M processor\b|\bVIA C7-M Processor\b|\bGeode\(TM\)\B)/i && $_->{'cpu MHz'} < 1500 } @cpus);
}
+=item has_low_resources()
+
+Is it a low ressource machine?
+
+=cut
+
sub has_low_resources() {
availableRamMB() < 100 || arch() =~ /i.86/ && ix86_cpu_frequency() < 350;
}
+=item need_light_desktop()
+
+Does it need a light desktop (netbook or low ressources machine)?
+
+=cut
+
sub need_light_desktop() {
has_low_resources() || is_netbook_nettop();
}
+=item has_cpu_flag($flag)
+
+Does CPU has this flag
+
+=cut
+
sub has_cpu_flag {
my ($flag) = @_;
cat_('/proc/cpuinfo') =~ /^flags.*\b$flag\b/m;
}
+=item sub matching_types()
+
+Returns a hash of flags (laptop, hyperv, touchpad, 64bit, wireless, ...)
+
+=cut
+
sub matching_types() {
+{
mips_lemote => is_mips_lemote(),
@@ -1251,6 +1572,12 @@ sub matching_types() {
};
}
+=item sub hasCPUMicrocode()
+
+Does CPU need microcode updates?
+
+=cut
+
sub hasCPUMicrocode() {
state $hasCPUMicrocode;
if (!defined $hasCPUMicrocode) {
@@ -1259,14 +1586,41 @@ sub hasCPUMicrocode() {
return $hasCPUMicrocode;
}
+=item sub hasCPUFreq()
+
+Does CPU support cpufreq?
+
+=cut
+
sub hasCPUFreq() {
require cpufreq;
to_bool(cpufreq::get_modules())
|| cat_('/proc/cpuinfo') =~ /AuthenticAMD/ && arch() =~ /x86_64/
|| cat_('/proc/cpuinfo') =~ /model name.*Intel\(R\) Core\(TM\)2 CPU/;
}
+
+=item sub hasWacom()
+
+is there a Wacom tablet?
+
+=cut
+
sub hasWacom() { find { $_->{vendor} == 0x056a || $_->{driver} =~ /wacom/ } usb_probe() }
+
+=item sub hasTouchpad()
+
+is there a touchpad?
+
+=cut
+
sub hasTouchpad() { any { $_->{Synaptics} || $_->{ALPS} || $_->{Elantech} } getInputDevices() }
+
+=item sub hasNumpad()
+
+is there a numeric pad?
+
+=cut
+
sub hasNumpad() { any { $_->{Numpad} } getInputDevices() }
sub usbWacom() { grep { $_->{vendor} eq '056a' } getInputDevices() }
@@ -1391,6 +1745,14 @@ sub suggest_mount_point {
$name;
}
+=back
+
+=head2 SEE ALSO
+
+See L<hardware_detection> for the overall view.
+
+=cut
+
1;
#- Local Variables: