diff options
Diffstat (limited to 'perl-install/modalias.pm')
| -rw-r--r-- | perl-install/modalias.pm | 104 | 
1 files changed, 104 insertions, 0 deletions
| diff --git a/perl-install/modalias.pm b/perl-install/modalias.pm new file mode 100644 index 000000000..e1b61edc0 --- /dev/null +++ b/perl-install/modalias.pm @@ -0,0 +1,104 @@ +package modalias; + +# TODO: +# - be faster (Elapsed time: lspcidrake.pl ~ 0.28s instead of 0.12s for old lspcidrake + +use strict; +use MDK::Common; +use c; + +my @config_groups = ( +    [ +	"/lib/module-init-tools/modprobe.default", +	"/etc/modprobe.conf", +	"/etc/modprobe.d", +    ], +); +my @system_groups = ( +    [ +        "/lib/module-init-tools/ldetect-lst-modules.alias", +    ], +    [ +        "/lib/modules/" . c::kernel_version() . "/modules.alias", +    ], +); +my @classes = qw(ide ieee1394 input pci pcmcia pnp serio usb); +my @alias_groups; + +my $alias_re = qr/^\s*alias\s+(([^:]+):\S+)\s+(\S+)$/; + +sub alias_to_ids { +    my ($alias) = @_; +    my ($vendor, $device); +    # returns (vendor, device) +    if (($vendor, $device) = $alias =~ /:v([0-9A-F]{4})[dp]([0-9A-F]{4})/) { +        return ($vendor, $device); +    } elsif (($vendor, $device) = $alias =~ /:v0{4}([0-9A-F]{4})[dp]0{4}([0-9A-F]{4})/) { +        return ($vendor, $device); +    } +} + +sub parse_path { +    my ($group, $path) = @_; +    if (-d $path) { +        parse_path($group, "$path/$_") foreach all($path); +    } elsif (-f $path) { +        foreach (cat_($path)) { +            if (my ($alias, $class, $module) = $_ =~ $alias_re) { +                if (member($class, @classes)) { +                    my ($vendor, $device) = alias_to_ids($alias); +                    if ($vendor) { +                        $group->{$class} ||= {}; +                        $group->{$class}{$vendor} ||= {}; +                        $group->{$class}{$vendor}{$device} ||= []; +                        push @{$group->{$class}{$vendor}{$device}}, $alias, $module; +                    } else { +                        push @{$group->{$class}{other}}, $alias, $module; +                    } +                } +            } +        } +    } +} + +sub parse_file_modules { +    my ($path) = @_; +    my %modules; +    foreach (cat_($path)) { +        if (my ($alias, undef, $module) = $_ =~ $alias_re) { +            push @{$modules{$module}}, $alias; +        } +    } +    \%modules; +} + +sub get_alias_groups { +    my ($o_skip_config) = @_; +    #- FIXME: only o_skip_config from the first call is considered +    @alias_groups = map { +        my $group = {}; +        parse_path($group, $_) foreach @$_; +        $group; +    } if_(!$o_skip_config, @config_groups), @system_groups unless @alias_groups; +    @alias_groups; +} + +sub get_modules { +    my ($modalias, $o_skip_config) = @_; +    my ($class) = $modalias =~ /^([^:]+):\S+$/; +    my ($vendor, $device) = alias_to_ids($modalias); +    $class && member($class, @classes) or return; + +    require File::FnMatch; +    foreach my $group (get_alias_groups($o_skip_config)) { +        my @aliases; +        foreach my $subgroup ($group->{$class}{$vendor}{$device}, $group->{$class}{other}) { +            foreach (group_by2(@$subgroup)) { +                File::FnMatch::fnmatch($_->[0], $modalias) and push @aliases, $_->[1]; +            } +        } +        return uniq(@aliases) if @aliases; +    } +} + +1; | 
