summaryrefslogtreecommitdiffstats
path: root/convert/uniquify-modalias.pl
blob: 830a37d34142901566678719d225c94b06f43944 (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
139
140
141
142
143
144
145
146
147
148
#!/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 = (
    "pata_marvell", #- prefer over ahci since ahci need marvel_enabled=1 to make it work (#43975)
    "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
    "p54pci", #- prefer over prism54
    "p54usb", #- prefer over prism54
    "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 = (
    #- defer *piix over ahci (install will still try both ahci and ata_piix), depends on BIOS settings
    #-   do it without explicitely listing ahci in preferred modules,
    #-   to allow ahci to be overriden by pata_marvell
    #- ata_piix will still be preferred over piix, because ata_piix is in the disk/sata preferred category
    "ata_piix", "piix",
    "gspca", #- kernel hackers value it as poorly coded
    "ir_usb", #- false positive because of pattern
    "usb_storage", #- false positive because we don't use subvendors/subdevices
    "snd_usb_audio", #- prefer video camera drivers if any
);
my @preferred_categories = (
    "disk/sata",
    "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 full implementation or "generic" libata module, not old IDE generic module
    "disk/ide" => [ "ide_pci_generic" ],
    "disk/sata" => [ "ata_generic", "pata_acpi" ],
    "input/tablet" => [ "usbmouse" ],
);

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 = map {
	my $l = list_modules::module2category($_->[1]);
	@{$category_deferred_modules{$l} || []};
    } @modules;

    @modules > 1 || @category_deferred_modules or return;

    my @non_ignored = grep_non_matching(\@modules, [ @ignored_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;
    } else {
        my @non_deferred = grep_non_matching(\@modules, [ @category_deferred_modules ]);
        if (@non_deferred == 1) {
            print "alias $modalias $non_deferred[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);
        }
    }
}