summaryrefslogtreecommitdiffstats
path: root/convert/uniquify-modalias.pl
blob: 259fd16082049fe80711ca3ae040c9c4acff4f08 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/perl

use lib qw(/usr/lib/libDrakX);
use File::FnMatch;
use MDK::Common;
use list_modules;
use modalias;

#- known bugs:
#- o does not match subvendors, they have to be handled on a case-by-case basis
#- o does not match PCI class (thus ahci won't match jmicron devices)

my @ignored_modules = (
    "intelfb", "savagefb", "tdfxfb", qr/_agp$/,
    qr/_rng$/,
);
my @preferred_modules = (
    "ahci", #- prefer over ata_piix (install will still try both), depends on BIOS settins
            #- do not prefer ata_piix, since it would override piix choice
    "bcm43xx", #- prefer over b43, b43legacy and ssb
    "dpt_i2o", #- prefer over i2o_core
    "dmfe", #- prefer over tulip, it only lists supported devices
    "c4", #- subvendors listed in c4 driver seems not to be supported by DAC960
    "i2c_viapro", #- prefer over via686a
    "ipr", #- subvendors listed in ipr driver seems not to be supported by DAC960
    "mxser_new", #- experimental clone of mxser
    "pata_netcell", "pata_ns87410", #- no non-libata implementation, prefer over generic module
    "prism54", #- prefer over p54pci
    "ipw3945", #- prefer over iwl3945, which has some stability/performance issues
    "rt2400", "rt2500", "rt2570", "rt61", "rt73", #- prefer legacy Ralink drivers
    "skge", #- prefer over sk98lin
    qr/^snd_/, #- prefer alsa drivers
    "sx", #- prefer over specialix (sx matches subvendors)
);
my @depreciated_modules = (
    "generic", #- prefer full implementation
    "gspca", #- kernel hackers value it as poorly coded
    "ir_usb", #- false positive because of pattern
    qr/^pata_/, #- don't use libata drivers for now
    "usb_storage", #- false positive because we don't use subvendors/subdevices
);
my @preferred_categories = (
    "disk/ide",
    "disk/scsi",
);
#- For the following categories, the deferred modules are ignored, and
#- an explicit alias is set even if only one module match exactly.
#- This allows to workaround modules having class wildcards, which isn't supported.
my %category_deferred_modules = (
    #- prefer "generic" non-libata module or full implementation
    "disk/ide" => [ "ata_generic" ],
    "disk/sata" => [ "ata_generic" ],
);

sub build_modalias {
    my ($class, $vendor, $device) = @_;
    {
        pci => "pci:v0000${vendor}d0000${device}sv*sd*bc*i*",
        usb => "usb:v${vendor}p${device}d*dc*dsc*dp*ic*isc*ip*",
    }->{$class};
}

sub match_module {
    my ($module, $pattern) = @_;
    ref $pattern eq 'Regexp' ? $module =~ $pattern : $module eq $pattern;
}

sub grep_non_matching {
    my ($modules, $list) = @_;
    grep {
        my $m = $_->[1];
        every { !match_module($m, $_) } @$list;
    } @$modules;
}

sub grep_matching {
    my ($modules, $list) = @_;
    grep {
        my $m = $_->[1];
        grep { match_module($m, $_) } @$list;
    } @$modules;
}

sub print_module {
    my ($modalias, $aliases, $class_other) = @_;
    my @aliases = group_by2(@$aliases);
    my @other = grep { File::FnMatch::fnmatch($_->[0], $modalias) } @$class_other;
    my @modules = uniq_ { $_->[1] } @aliases, @other;

    @modules or return;

    my @category_deferred_modules;
    foreach (map { list_modules::module2category($_->[1]) } @modules) {
        push @category_deferred_modules, @{$category_deferred_modules{$_} || []}
    }

    @modules > 1 || @category_deferred_modules or return;

    my @non_ignored = grep_non_matching(\@modules, [ @ignored_modules, @category_deferred_modules ]);
    if (@non_ignored == 1) {
        print "alias $modalias $non_ignored[0][1]\n";
        return;
    } elsif (@non_ignored == 0) {
        print "alias $modalias off\n";
        return;
    }

    @modules = @non_ignored;
    my @non_depreciated = grep_non_matching(\@modules, \@depreciated_modules);
    if (@non_depreciated == 1) {
        print "alias $modalias $non_depreciated[0][1]\n";
        return;
    }

    @modules = @non_depreciated if @non_depreciated > 1;
    my @preferred = grep_matching(\@modules, \@preferred_modules);
    @preferred or @preferred = grep { member(module2category($_->[1]), @preferred_categories) } @modules;
    if (@preferred == 1) {
        print "alias $modalias $preferred[0][1]\n";
        return;
    }

    print STDERR "unable to choose for $modalias " . join(" ", map { $_->[1] } @modules) . "\n";
}

my $alias_group = {};
modalias::parse_path($alias_group, "../lst/fallback-modules.alias");

foreach my $class (qw(pci pcmcia usb)) {
    my @class_other = group_by2(@{$alias_group->{$class}{other}});
    foreach my $vendor (sort(keys(%{$alias_group->{$class}}))) {
        $vendor eq "other" and next;
        foreach my $device (sort(keys(%{$alias_group->{$class}{$vendor}}))) {
            my $modalias = build_modalias($class, $vendor, $device);
            print_module($modalias, $alias_group->{$class}{$vendor}{$device}, \@class_other);
        }
    }
}