summary refs log blame commit diff
path: root/modules/installer/tools/nixos-hardware-scan.pl
blob: 31b07a57280361a71737dce0b863c6f023cc4c70 (plain) (tree)
1
2
3
4
5
6
7
8
9
                     




                   
               

                             
                        

 





                                        









































                                                                    
                
 











                                                             


                                          
















                                                                     

     






                                                                             
                                                                              
      
                                                                        


                                  


                                                                     
                                                                  
                              

                                                                             
 
                                                                   
                              


                                                      


                                                                        




















                                                             


                                              





















                                                             



                                              







                                                                    




                                                                         





















                                  


                       
                                 
                        
                              
     


                

                                                                     
                                                           
                                                   

             

                                                       
                                   
 
 



                                                     


                                                      
 
                      
       
   
#! @perl@/bin/perl -w

use File::Spec;
use File::Basename;


my @attrs = ();
my @kernelModules = ();
my @initrdKernelModules = ();
my @modulePackages = ();


sub debug {
    return unless defined $ENV{"DEBUG"};
    print STDERR @_;
}


# Read a file, returning undef if the file cannot be opened.
sub readFile {
    my $filename = shift;
    my $res;
    if (open FILE, "<$filename") {
        my $prev = $/;
        undef $/;
        $res = <FILE>;
        $/ = $prev;
        close FILE;
        chomp $res;
    }
    return $res;
}


my $cpuinfo = readFile "/proc/cpuinfo";


sub hasCPUFeature {
    my $feature = shift;
    return $cpuinfo =~ /^flags\s*:.* $feature( |$)/m;
}


# Detect the number of CPU cores.
my $cpus = scalar (grep {/^processor\s*:/} (split '\n', $cpuinfo));


# CPU frequency scaling.  Not sure about this test.
push @kernelModules, "acpi-cpufreq" if hasCPUFeature "acpi";


# Virtualization support?
push @kernelModules, "kvm-intel" if hasCPUFeature "vmx";
push @kernelModules, "kvm-amd" if hasCPUFeature "svm";


# Look at the PCI devices and add necessary modules.  Note that most
# modules are auto-detected so we don't need to list them here.
# However, some are needed in the initrd to boot the system.

my $videoDriver;

sub pciCheck {
    my $path = shift;
    my $vendor = readFile "$path/vendor";
    my $device = readFile "$path/device";
    my $class = readFile "$path/class";
    
    my $module;
    if (-e "$path/driver/module") {
        $module = basename `readlink -f $path/driver/module`;
        chomp $module;
    }
    
    debug "$path: $vendor $device $class";
    debug " $module" if defined $module;
    debug "\n";

    if (defined $module) {
        # See the bottom of http://pciids.sourceforge.net/pci.ids for
        # device classes.
        if (# Mass-storage controller.  Definitely important.
            $class =~ /^0x01/ ||

            # Firewire controller.  A disk might be attached.
            $class =~ /^0x0c00/ ||

            # USB controller.  Needed if we want to use the
            # keyboard when things go wrong in the initrd.
            $class =~ /^0x0c03/
            )
        {
            push @initrdKernelModules, $module;
        }
    }

    # broadcom STA driver (wl.ko)
    # list taken from http://www.broadcom.com/docs/linux_sta/README.txt
    if ($vendor eq "0x14e4" &&
        ($device eq "0x4311" || $device eq "0x4312" || $device eq "0x4313" ||
         $device eq "0x4315" || $device eq "0x4327" || $device eq "0x4328" ||
         $device eq "0x4329" || $device eq "0x432a" || $device eq "0x432b" ||
         $device eq "0x432c" || $device eq "0x432d" || $device eq "0x4353" ||
         $device eq "0x4357" || $device eq "0x4358" || $device eq "0x4359" ) )
     {
        push @modulePackages, "config.boot.kernelPackages.broadcom_sta";
        push @kernelModules, "wl";
     }

    # Can't rely on $module here, since the module may not be loaded
    # due to missing firmware.  Ideally we would check modules.pcimap
    # here.
    push @attrs, "networking.enableIntel2200BGFirmware = true;" if
        $vendor eq "0x8086" &&
        ($device eq "0x1043" || $device eq "0x104f" || $device eq "0x4220" ||
         $device eq "0x4221" || $device eq "0x4223" || $device eq "0x4224");

    push @attrs, "networking.enableIntel3945ABGFirmware = true;" if
        $vendor eq "0x8086" &&
        ($device eq "0x4229" || $device eq "0x4230" ||
         $device eq "0x4222" || $device eq "0x4227");

    # Assume that all NVIDIA cards are supported by the NVIDIA driver.
    # There may be exceptions (e.g. old cards).
    $videoDriver = "nvidia" if $vendor eq "0x10de" && $class =~ /^0x03/;
}

foreach my $path (glob "/sys/bus/pci/devices/*") {
    pciCheck $path;
}


# Idem for USB devices.

sub usbCheck {
    my $path = shift;
    my $class = readFile "$path/bInterfaceClass";
    my $subclass = readFile "$path/bInterfaceSubClass";
    my $protocol = readFile "$path/bInterfaceProtocol";

    my $module;
    if (-e "$path/driver/module") {
        $module = basename `readlink -f $path/driver/module`;
        chomp $module;
    }
    
    debug "$path: $class $subclass $protocol";
    debug " $module" if defined $module;
    debug "\n";
 
    if (defined $module) {
        if (# Mass-storage controller.  Definitely important.
            $class eq "08" ||

            # Keyboard.  Needed if we want to use the
            # keyboard when things go wrong in the initrd.
            ($class eq "03" && $protocol eq "01")
            )
        {
            push @initrdKernelModules, $module;
        }
    }
}

foreach my $path (glob "/sys/bus/usb/devices/*") {
    if (-e "$path/bInterfaceClass") {
        usbCheck $path;
    }
}


# Add the modules for all block devices.

foreach my $path (glob "/sys/class/block/*") {
    my $module;
    if (-e "$path/device/driver/module") {
        $module = basename `readlink -f $path/device/driver/module`;
        chomp $module;
        push @initrdKernelModules, $module;
    }
}


if ($videoDriver) {
    push @attrs, "services.xserver.videoDrivers = [ \"$videoDriver\" ];";
}


# Generate the configuration file.

sub removeDups {
    my %seen;
    my @res = ();
    foreach my $s (@_) {
        if (!defined $seen{$s}) {
            $seen{$s} = "";
            push @res, $s;
        }
    }
    return @res;
}

sub toNixExpr {
    my $res = "";
    foreach my $s (@_) {
        $res .= " \"$s\"";
    }
    return $res;
}

sub multiLineList {
    my $indent = shift;
    my $res = "";
    $res = "\n" if scalar @_ > 0;
    foreach my $s (@_) {
        $res .= "$indent$s\n";
    }
    return $res;
}

my $initrdKernelModules = toNixExpr(removeDups @initrdKernelModules);
my $kernelModules = toNixExpr(removeDups @kernelModules);
my $modulePackages = toNixExpr(removeDups @modulePackages);
my $attrs = multiLineList("  ", removeDups @attrs);

print <<EOF ;
# This is a generated file.  Do not modify!
# Make changes to /etc/nixos/configuration.nix instead.
{ config, pkgs, modulesPath, ... }:

{
  require = [
    "\${modulesPath}/installer/scan/not-detected.nix"
  ];

  boot.initrd.kernelModules = [$initrdKernelModules ];
  boot.kernelModules = [$kernelModules ];
  boot.extraModulePackages = [$modulePackages ];

  nix.maxJobs = $cpus;
$attrs}
EOF