Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/env perl
0002 # SPDX-License-Identifier: GPL-2.0-only
0003 
0004 # Copyright 2016 by Frank Rowand
0005 # Copyright 2016 by Gaurav Minocha
0006 #
0007 
0008 use strict 'refs';
0009 use strict subs;
0010 
0011 use Getopt::Long;
0012 
0013 $VUFX = "160610a";
0014 
0015 $script_name = $0;
0016 $script_name =~ s|^.*/||;
0017 
0018 
0019 # ----- constants for print_flags()
0020 
0021 # Position in string $pr_flags.  Range of 0..($num_pr_flags - 1).
0022 $pr_flag_pos_mcompatible       = 0;
0023 $pr_flag_pos_driver            = 1;
0024 $pr_flag_pos_mdriver           = 2;
0025 $pr_flag_pos_config            = 3;
0026 $pr_flag_pos_mconfig           = 4;
0027 $pr_flag_pos_node_not_enabled  = 5;
0028 $pr_flag_pos_white_list        = 6;
0029 $pr_flag_pos_hard_coded        = 7;
0030 $pr_flag_pos_config_hard_coded = 8;
0031 $pr_flag_pos_config_none       = 9;
0032 $pr_flag_pos_config_m          = 10;
0033 $pr_flag_pos_config_y          = 11;
0034 $pr_flag_pos_config_test_fail  = 12;
0035 
0036 $num_pr_flags = $pr_flag_pos_config_test_fail + 1;
0037 
0038 # flags in @pr_flag_value must be unique values to allow simple regular
0039 # expessions to work for --include_flags and --exclude_flags.
0040 # Convention: use upper case letters for potential issues or problems.
0041 
0042 @pr_flag_value = ('M', 'd', 'D', 'c', 'C', 'E', 'W', 'H', 'x', 'n', 'm', 'y', 'F');
0043 
0044 @pr_flag_help = (
0045     "multiple compatibles found for this node",
0046     "driver found for this compatible",
0047     "multiple drivers found for this compatible",
0048     "kernel config found for this driver",
0049     "multiple config options found for this driver",
0050     "node is not enabled",
0051     "compatible is white listed",
0052     "matching driver and/or kernel config is hard coded",
0053     "kernel config hard coded in Makefile",
0054     "one or more kernel config file options is not set",
0055     "one or more kernel config file options is set to 'm'",
0056     "one or more kernel config file options is set to 'y'",
0057     "one of more kernel config file options fails to have correct value"
0058 );
0059 
0060 
0061 # -----
0062 
0063 %driver_config = ();   # driver config array, indexed by driver source file
0064 %driver_count = ();    # driver_cnt, indexed by compatible
0065 %compat_driver = ();   # compatible driver array, indexed by compatible
0066 %existing_config = (); # existing config symbols present in given config file
0067                        # expected values are: "y", "m", a decimal number, a
0068                        # hex number, or a string
0069 
0070 # ----- magic compatibles, do not have a driver
0071 #
0072 # Will not search for drivers for these compatibles.
0073 
0074 %compat_white_list = (
0075        'none'                  => '1',
0076        'pci'                   => '1',
0077        'simple-bus'            => '1',
0078 );
0079 
0080 # Will not search for drivers for these compatibles.
0081 #
0082 # These compatibles have a very large number of false positives.
0083 #
0084 # 'hardcoded_no_driver' is a magic value.  Other code knows this
0085 # magic value.  Do not use 'no_driver' here!
0086 #
0087 # Revisit each 'hardcoded_no_driver' to see how the compatible
0088 # is used.  Are there drivers that can be provided?
0089 
0090 %driver_hard_code_list = (
0091        'cache'                 => ['hardcoded_no_driver'],
0092        'eeprom'                => ['hardcoded_no_driver'],
0093        'gpio'                  => ['hardcoded_no_driver'],
0094        'gpio-keys'             => ['drivers/input/keyboard/gpio_keys.c'],
0095        'i2c-gpio'              => ['drivers/i2c/busses/i2c-gpio.c'],
0096        'isa'                   => ['arch/mips/mti-malta/malta-dt.c',
0097                                     'arch/x86/kernel/devicetree.c'],
0098        'led'                   => ['hardcoded_no_driver'],
0099        'm25p32'                => ['hardcoded_no_driver'],
0100        'm25p64'                => ['hardcoded_no_driver'],
0101        'm25p80'                => ['hardcoded_no_driver'],
0102        'mtd-ram'               => ['drivers/mtd/maps/physmap_of.c'],
0103        'pwm-backlight'         => ['drivers/video/backlight/pwm_bl.c'],
0104        'spidev'                => ['hardcoded_no_driver'],
0105        'syscon'                => ['drivers/mfd/syscon.c'],
0106        'tlv320aic23'           => ['hardcoded_no_driver'],
0107        'wm8731'                => ['hardcoded_no_driver'],
0108 );
0109 
0110 # Use these config options instead of searching makefiles
0111 
0112 %driver_config_hard_code_list = (
0113 
0114        # this one needed even if %driver_hard_code_list is empty
0115        'no_driver'                             => ['no_config'],
0116        'hardcoded_no_driver'                   => ['no_config'],
0117 
0118        # drivers/usb/host/ehci-ppc-of.c
0119        # drivers/usb/host/ehci-xilinx-of.c
0120        #  are included from:
0121        #    drivers/usb/host/ehci-hcd.c
0122        #  thus the search of Makefile for the included .c files is incorrect
0123        # ehci-hcd.c wraps the includes with ifdef CONFIG_USB_EHCI_HCD_..._OF
0124        #
0125        # similar model for ohci-hcd.c (but no ohci-xilinx-of.c)
0126        #
0127        # similarly, uhci-hcd.c includes uhci-platform.c
0128 
0129        'drivers/usb/host/ehci-ppc-of.c'        => ['CONFIG_USB_EHCI_HCD',
0130                                                    'CONFIG_USB_EHCI_HCD_PPC_OF'],
0131        'drivers/usb/host/ohci-ppc-of.c'        => ['CONFIG_USB_OHCI_HCD',
0132                                                    'CONFIG_USB_OHCI_HCD_PPC_OF'],
0133 
0134        'drivers/usb/host/ehci-xilinx-of.c'     => ['CONFIG_USB_EHCI_HCD',
0135                                                    'CONFIG_USB_EHCI_HCD_XILINX'],
0136 
0137        'drivers/usb/host/uhci-platform.c'      => ['CONFIG_USB_UHCI_HCD',
0138                                                    'CONFIG_USB_UHCI_PLATFORM'],
0139 
0140        # scan_makefile will find only one of these config options:
0141        #    ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
0142        'arch/arm/mach-imx/platsmp.c'           => ['CONFIG_SOC_IMX6 && CONFIG_SMP',
0143                                                    'CONFIG_SOC_LS1021A && CONFIG_SMP'],
0144 );
0145 
0146 
0147 # 'virt/kvm/arm/.*' are controlled by makefiles in other directories,
0148 # using relative paths, such as 'KVM := ../../../virt/kvm'.  Do not
0149 # add complexity to find_kconfig() to deal with this.  There is a long
0150 # term intent to change the kvm related makefiles to the normal kernel
0151 # style.  After that is done, this entry can be removed from the
0152 # black_list_driver.
0153 
0154 @black_list_driver = (
0155        # kvm no longer a problem after commit 503a62862e8f in 4.7-rc1
0156        # 'virt/kvm/arm/.*',
0157 );
0158 
0159 
0160 sub usage()
0161 {
0162        print
0163 "
0164 Usage: $script_name [options] device-tree...
0165 
0166     device_tree is: dts_file | dtb_file | proc_device-tree
0167 
0168 
0169 Valid options:
0170      -c FILE             Read kernel config options from FILE
0171     --config FILE        synonym for 'c'
0172     --config-format      config file friendly output format
0173     --exclude-flag FLAG  exclude entries with a matching flag
0174      -h                  Display this message and exit
0175     --help               synonym for 'h'
0176     --black-list-driver  use driver black list
0177     --white-list-config  use config white list
0178     --white-list-driver  use driver white list
0179     --include-flag FLAG  include only entries with a matching flag
0180     --include-suspect    include only entries with an uppercase flag
0181     --short-name         do not show the path portion of the node name
0182     --show-lists         report of white and black lists
0183     --version            Display program version and exit
0184 
0185 
0186   Report driver source files that match the compatibles in the device
0187   tree file and the kernel config options that enable the driver source
0188   files.
0189 
0190   This program must be run in the root directory of a Linux kernel
0191   source tree.
0192 
0193   The default format is a report that is intended to be easily human
0194   scannable.
0195 
0196   An alternate format can be selected by --config-format.  This will
0197   create output that can easily be edited to create a fragment that can
0198   be appended to the existing kernel config file.  Each entry consists of
0199   multiple lines.  The first line reports flags, the node path, compatible
0200   value, driver file matching the compatible, configuration options, and
0201   current values of the configuration options.  For each configuration
0202   option, the following lines report the current value and the value that
0203   is required for the driver file to be included in the kernel.
0204 
0205   If a large number of drivers or config options is listed for a node,
0206   and the '$pr_flag_value[$pr_flag_pos_hard_coded]' flag is set consider using --white-list-config and/or
0207   --white-list-driver.  If the white list option suppresses the correct
0208   entry please report that as a bug.
0209 
0210   CAUTION:
0211      This program uses heuristics to guess which driver(s) support each
0212      compatible string and which config option(s) enables the driver(s).
0213      Do not believe that the reported information is fully correct.
0214      This program is intended to aid the process of determining the
0215      proper kernel configuration for a device tree, but this is not
0216      a fully automated process -- human involvement may still be
0217      required!
0218 
0219      The driver match heuristic used is to search for source files
0220      containing the compatible string enclosed in quotes.
0221 
0222      This program might not be able to find all drivers matching a
0223      compatible string.
0224 
0225      Some makefiles are overly clever.  This program was not made
0226      complex enough to handle them.  If no config option is listed
0227      for a driver, look at the makefile for the driver source file.
0228      Even if a config option is listed for a driver, some other
0229      available config options may not be listed.
0230 
0231   FLAG values:
0232 ";
0233 
0234        for ($k = 0; $k < $num_pr_flags; $k++) {
0235                printf "     %s   %s\n", $pr_flag_value[$k], $pr_flag_help[$k];
0236        }
0237 
0238        print
0239 "
0240      Upper case letters indicate potential issues or problems.
0241 
0242   The flag:
0243 
0244 ";
0245 
0246        $k = $pr_flag_pos_hard_coded;
0247        printf "     %s   %s\n", $pr_flag_value[$k], $pr_flag_help[$k];
0248 
0249        print
0250 "
0251   will be set if the config or driver is in the white lists, even if
0252   --white-list-config and --white-list-driver are not specified.
0253   This is a hint that 1) many of these reported lines are likely to
0254   be incorrect, and 2) using those options will reduce the number of
0255   drivers and/or config options reported.
0256 
0257   --white-list-config and --white-list-driver may not be accurate if this
0258   program is not well maintained.  Use them with appropriate skepticism.
0259   Use the --show-lists option to report the values in the list.
0260 
0261   Return value:
0262     0   if no error
0263     1   error processing command line
0264     2   unable to open or read kernel config file
0265     3   unable to open or process input device tree file(s)
0266 
0267   EXAMPLES:
0268 
0269      dt_to_config arch/arm/boot/dts/my_dts_file.dts
0270 
0271        Basic report.
0272 
0273      dt_to_config \\
0274         --config \${KBUILD_OUTPUT}/.config \\
0275         arch/\${ARCH}/boot/dts/my_dts_file.dts
0276 
0277        Full report, with config file issues noted.
0278 
0279      dt_to_config --include-suspect \\
0280         --config \${KBUILD_OUTPUT}/.config \\
0281         arch/\${ARCH}/boot/dts/my_dts_file.dts
0282 
0283        Report of node / compatible string / driver tuples that should
0284        be further investigated.  A node may have multiple compatible
0285        strings.  A compatible string may be matched by multiple drivers.
0286        A driver may have config file issues noted.  The compatible string
0287        and/or driver may be in the white lists.
0288 
0289      dt_to_config --include-suspect --config-format \\
0290         --config ${KBUILD_OUTPUT}/.config \\
0291         arch/\${ARCH}/boot/dts/my_dts_file.dts
0292 
0293        Report of node / compatible string / driver tuples that should
0294        be further investigated.  The report can be edited to uncomment
0295        the config options to select the desired tuple for a given node.
0296        A node may have multiple compatible strings.  A compatible string
0297        may be matched by multiple drivers.  A driver may have config file
0298        issues noted.  The compatible string and/or driver may be in the
0299        white lists.
0300 
0301 ";
0302 }
0303 
0304 sub set_flag()
0305 {
0306        # pr_flags_ref is a reference to $pr_flags
0307 
0308        my $pr_flags_ref = shift;
0309        my $pos          = shift;
0310 
0311        substr $$pr_flags_ref, $pos, 1, $pr_flag_value[$pos];
0312 
0313        return $pr_flags;
0314 }
0315 
0316 sub print_flags()
0317 {
0318        # return 1 if anything printed, else 0
0319 
0320        # some fields of pn_arg_ref might not be used in this function, but
0321        # extract all of them anyway.
0322        my $pn_arg_ref     = shift;
0323 
0324        my $compat         = $pn_arg_ref->{compat};
0325        my $compatible_cnt = $pn_arg_ref->{compatible_cnt};
0326        my $config         = $pn_arg_ref->{config};
0327        my $config_cnt     = $pn_arg_ref->{config_cnt};
0328        my $driver         = $pn_arg_ref->{driver};
0329        my $driver_cnt     = $pn_arg_ref->{driver_cnt};
0330        my $full_node      = $pn_arg_ref->{full_node};
0331        my $node           = $pn_arg_ref->{node};
0332        my $node_enabled   = $pn_arg_ref->{node_enabled};
0333        my $white_list     = $pn_arg_ref->{white_list};
0334 
0335        my $pr_flags       = '-' x $num_pr_flags;
0336 
0337 
0338        # ----- set flags in $pr_flags
0339 
0340        if ($compatible_cnt > 1) {
0341                &set_flag(\$pr_flags, $pr_flag_pos_mcompatible);
0342        }
0343 
0344        if ($config_cnt > 1) {
0345                &set_flag(\$pr_flags, $pr_flag_pos_mconfig);
0346        }
0347 
0348        if ($driver_cnt >= 1) {
0349                &set_flag(\$pr_flags, $pr_flag_pos_driver);
0350        }
0351 
0352        if ($driver_cnt > 1) {
0353                &set_flag(\$pr_flags, $pr_flag_pos_mdriver);
0354        }
0355 
0356        # These strings are the same way the linux kernel tests.
0357        # The ePapr lists of values is slightly different.
0358        if (!(
0359              ($node_enabled eq "") ||
0360              ($node_enabled eq "ok") ||
0361              ($node_enabled eq "okay")
0362             )) {
0363                &set_flag(\$pr_flags, $pr_flag_pos_node_not_enabled);
0364        }
0365 
0366        if ($white_list) {
0367                &set_flag(\$pr_flags, $pr_flag_pos_white_list);
0368        }
0369 
0370        if (exists($driver_hard_code_list{$compat}) ||
0371            (exists($driver_config_hard_code_list{$driver}) &&
0372             ($driver ne "no_driver"))) {
0373                &set_flag(\$pr_flags, $pr_flag_pos_hard_coded);
0374        }
0375 
0376        my @configs = split(' && ', $config);
0377        for $configs (@configs) {
0378                $not = $configs =~ /^!/;
0379                $configs =~ s/^!//;
0380 
0381                if (($configs ne "no_config") && ($configs ne "no_makefile")) {
0382                        &set_flag(\$pr_flags, $pr_flag_pos_config);
0383                }
0384 
0385                if (($config_cnt >= 1) &&
0386                    ($configs !~ /CONFIG_/) &&
0387                    (($configs ne "no_config") && ($configs ne "no_makefile"))) {
0388                        &set_flag(\$pr_flags, $pr_flag_pos_config_hard_coded);
0389                }
0390 
0391                my $existing_config = $existing_config{$configs};
0392                if ($existing_config eq "m") {
0393                        &set_flag(\$pr_flags, $pr_flag_pos_config_m);
0394                        # Possible fail, depends on whether built in or
0395                        # module is desired.
0396                        &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail);
0397                } elsif ($existing_config eq "y") {
0398                        &set_flag(\$pr_flags, $pr_flag_pos_config_y);
0399                        if ($not) {
0400                                &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail);
0401                        }
0402                } elsif (($config_file) && ($configs =~ /CONFIG_/)) {
0403                        &set_flag(\$pr_flags, $pr_flag_pos_config_none);
0404                        if (!$not) {
0405                                &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail);
0406                        }
0407                }
0408        }
0409 
0410        # ----- include / exclude filters
0411 
0412        if ($include_flag_pattern && ($pr_flags !~ m/$include_flag_pattern/)) {
0413                return 0;
0414        }
0415 
0416        if ($exclude_flag_pattern && ($pr_flags =~ m/$exclude_flag_pattern/)) {
0417                return 0;
0418        }
0419 
0420        if ($config_format) {
0421                print "# ";
0422        }
0423        print "$pr_flags : ";
0424 
0425        return 1;
0426 }
0427 
0428 
0429 sub print_node()
0430 {
0431        # return number of lines printed
0432 
0433        # some fields of pn_arg_ref might not be used in this function, but
0434        # extract all of them anyway.
0435        my $pn_arg_ref     = shift;
0436 
0437        my $compat         = $pn_arg_ref->{compat};
0438        my $compatible_cnt = $pn_arg_ref->{compatible_cnt};
0439        my $config         = $pn_arg_ref->{config};
0440        my $config_cnt     = $pn_arg_ref->{config_cnt};
0441        my $driver         = $pn_arg_ref->{driver};
0442        my $driver_cnt     = $pn_arg_ref->{driver_cnt};
0443        my $full_node      = $pn_arg_ref->{full_node};
0444        my $node           = $pn_arg_ref->{node};
0445        my $node_enabled   = $pn_arg_ref->{node_enabled};
0446        my $white_list     = $pn_arg_ref->{white_list};
0447 
0448        my $separator;
0449 
0450        if (! &print_flags($pn_arg_ref)) {
0451                return 0;
0452        }
0453 
0454 
0455        if ($short_name) {
0456                print "$node";
0457        } else {
0458                print "$full_node";
0459        }
0460        print " : $compat : $driver : $config : ";
0461 
0462        my @configs = split(' && ', $config);
0463 
0464        if ($config_file) {
0465                for $configs (@configs) {
0466                        $configs =~ s/^!//;
0467                        my $existing_config = $existing_config{$configs};
0468                        if (!$existing_config) {
0469                                # check for /-m/, /-y/, or /-objs/
0470                                if ($configs !~ /CONFIG_/) {
0471                                        $existing_config = "x";
0472                                };
0473                        };
0474                        if ($existing_config) {
0475                                print "$separator", "$existing_config";
0476                                $separator = ", ";
0477                        } else {
0478                                print "$separator", "n";
0479                                $separator = ", ";
0480                        }
0481                }
0482        } else {
0483                print "none";
0484        }
0485 
0486        print "\n";
0487 
0488        if ($config_format) {
0489                for $configs (@configs) {
0490                        $not = $configs =~ /^!/;
0491                        $configs =~ s/^!//;
0492                        my $existing_config = $existing_config{$configs};
0493 
0494                        if ($not) {
0495                                if ($configs !~ /CONFIG_/) {
0496                                        print "# $configs\n";
0497                                } elsif ($existing_config eq "m") {
0498                                        print "# $configs is m\n";
0499                                        print "# $configs=n\n";
0500                                } elsif ($existing_config eq "y") {
0501                                        print "# $configs is set\n";
0502                                        print "# $configs=n\n";
0503                                } else {
0504                                        print "# $configs is not set\n";
0505                                        print "# $configs=n\n";
0506                                }
0507 
0508                        } else {
0509                                if ($configs !~ /CONFIG_/) {
0510                                        print "# $configs\n";
0511                                } elsif ($existing_config eq "m") {
0512                                        print "# $configs is m\n";
0513                                        print "# $configs=y\n";
0514                                } elsif ($existing_config eq "y") {
0515                                        print "# $configs is set\n";
0516                                        print "# $configs=y\n";
0517                                } else {
0518                                        print "# $configs is not set\n";
0519                                        print "# $configs=y\n";
0520                                }
0521                        }
0522                }
0523        }
0524 
0525        return 1;
0526 }
0527 
0528 
0529 sub scan_makefile
0530 {
0531        my $pn_arg_ref    = shift;
0532        my $driver        = shift;
0533 
0534        # ----- Find Kconfig symbols that enable driver
0535 
0536        my ($dir, $base) = $driver =~ m{(.*)/(.*).c};
0537 
0538        my $makefile = $dir . "/Makefile";
0539        if (! -r $makefile) {
0540                $makefile = $dir . "/Kbuild";
0541        }
0542        if (! -r $makefile) {
0543                my $config;
0544 
0545                $config = 'no_makefile';
0546                push @{ $driver_config{$driver} }, $config;
0547                return;
0548        }
0549 
0550        if (!open(MAKEFILE_FILE, "<", "$makefile")) {
0551                return;
0552        }
0553 
0554        my $line;
0555        my @config;
0556        my @if_config;
0557        my @make_var;
0558 
0559        NEXT_LINE:
0560        while ($next_line = <MAKEFILE_FILE>) {
0561                my $config;
0562                my $if_config;
0563                my $ifdef;
0564                my $ifeq;
0565                my $ifndef;
0566                my $ifneq;
0567                my $ifdef_config;
0568                my $ifeq_config;
0569                my $ifndef_config;
0570                my $ifneq_config;
0571 
0572                chomp($next_line);
0573                $line = $line . $next_line;
0574                if ($next_line =~ /\\$/) {
0575                        $line =~ s/\\$/ /;
0576                        next NEXT_LINE;
0577                }
0578                if ($line =~ /^\s*#/) {
0579                        $line = "";
0580                        next NEXT_LINE;
0581                }
0582 
0583                # -----  condition ... else ... endif
0584 
0585                if ($line =~ /^([ ]\s*|)else\b/) {
0586                        $if_config = "!" . pop @if_config;
0587                        $if_config =~ s/^!!//;
0588                        push @if_config, $if_config;
0589                        $line =~ s/^([ ]\s*|)else\b//;
0590                }
0591 
0592                ($null, $ifeq_config,  $ifeq_config_val )  = $line =~ /^([ ]\s*|)ifeq\b.*\b(CONFIG_[A-Za-z0-9_]*)(.*)/;
0593                ($null, $ifneq_config, $ifneq_config_val)  = $line =~ /^([ ]\s*|)ifneq\b.*\b(CONFIG_[A-Za-z0-9_]*)(.*)/;
0594                ($null, $ifdef_config)                     = $line =~ /^([ ]\s*|)ifdef\b.*\b(CONFIG_[A-Za-z0-9_]*)/;
0595                ($null, $ifndef_config)                    = $line =~ /^([ ]\s*|)ifndef\b.*\b(CONFIG_[A-Za-z0-9_]*)/;
0596 
0597                ($null, $ifeq)   = $line =~ /^([ ]\s*|)ifeq\b\s*(.*)/;
0598                ($null, $ifneq)  = $line =~ /^([ ]\s*|)ifneq\b\s*(.*)/;
0599                ($null, $ifdef)  = $line =~ /^([ ]\s*|)ifdef\b\s*(.*)/;
0600                ($null, $ifndef) = $line =~ /^([ ]\s*|)ifndef\b\s*(.*)/;
0601 
0602                # Order of tests is important.  Prefer "CONFIG_*" regex match over
0603                # less specific regex match.
0604                if ($ifdef_config) {
0605                        $if_config = $ifdef_config;
0606                } elsif ($ifeq_config) {
0607                        if ($ifeq_config_val =~ /y/) {
0608                                $if_config = $ifeq_config;
0609                        } else {
0610                                $if_config = "!" . $ifeq_config;
0611                        }
0612                } elsif ($ifndef_config) {
0613                        $if_config = "!" . $ifndef_config;
0614                } elsif ($ifneq_config) {
0615                        if ($ifneq_config_val =~ /y/) {
0616                                $if_config = "!" . $ifneq_config;
0617                        } else {
0618                                $if_config = $ifneq_config;
0619                        }
0620                } elsif ($ifdef) {
0621                        $if_config = $ifdef;
0622                } elsif ($ifeq) {
0623                        $if_config = $ifeq;
0624                } elsif ($ifndef) {
0625                        $if_config = "!" . $ifndef;
0626                } elsif ($ifneq) {
0627                        $if_config = "!" . $ifneq;
0628                } else {
0629                        $if_config = "";
0630                }
0631                $if_config =~ s/^!!//;
0632 
0633                if ($if_config) {
0634                        push @if_config, $if_config;
0635                        $line = "";
0636                        next NEXT_LINE;
0637                }
0638 
0639                if ($line =~ /^([ ]\s*|)endif\b/) {
0640                        pop @if_config;
0641                        $line = "";
0642                        next NEXT_LINE;
0643                }
0644 
0645                # ----- simple CONFIG_* = *.[co]  or  xxx [+:?]*= *.[co]
0646                # Most makefiles select on *.o, but
0647                # arch/powerpc/boot/Makefile selects on *.c
0648 
0649                ($config) = $line =~ /(CONFIG_[A-Za-z0-9_]+).*\b$base.[co]\b/;
0650 
0651                # ----- match a make variable instead of *.[co]
0652                # Recursively expanded variables are not handled.
0653 
0654                if (!$config) {
0655                        my $make_var;
0656                        ($make_var) = $line =~ /\s*(\S+?)\s*[+:\?]*=.*\b$base.[co]\b/;
0657                        if ($make_var) {
0658                                if ($make_var =~ /[a-zA-Z0-9]+-[ym]/) {
0659                                        $config = $make_var;
0660                                } elsif ($make_var =~ /[a-zA-Z0-9]+-objs/) {
0661                                        $config = $make_var;
0662                                } else {
0663                                        push @make_var, $make_var;
0664                                }
0665                        }
0666                }
0667 
0668                if (!$config) {
0669                        for $make_var (@make_var) {
0670                                ($config) = $line =~ /(CONFIG_[A-Za-z0-9_]+).*\b$make_var\b/;
0671                                last if ($config);
0672                        }
0673                }
0674 
0675                if (!$config) {
0676                        for $make_var (@make_var) {
0677                                ($config) = $line =~ /\s*(\S+?)\s*[+:\?]*=.*\b$make_var\b/;
0678                                last if ($config);
0679                        }
0680                }
0681 
0682                # ----- next if no config found
0683 
0684                if (!$config) {
0685                        $line = "";
0686                        next NEXT_LINE;
0687                }
0688 
0689                for $if_config (@if_config) {
0690                        $config = $if_config . " && " . $config;
0691                }
0692 
0693                push @{ $driver_config{$driver} }, $config;
0694 
0695                $line = "";
0696        }
0697 
0698        close(MAKEFILE_FILE);
0699 
0700 }
0701 
0702 
0703 sub find_kconfig
0704 {
0705        my $pn_arg_ref    = shift;
0706        my $driver        = shift;
0707 
0708        my $lines_printed = 0;
0709        my @configs;
0710 
0711        if (!@{ $driver_config{$driver} }) {
0712                &scan_makefile($pn_arg_ref, $driver);
0713                if (!@{ $driver_config{$driver} }) {
0714                        push @{ $driver_config{$driver} }, "no_config";
0715                }
0716        }
0717 
0718        @configs = @{ $driver_config{$driver} };
0719 
0720        $$pn_arg_ref{config_cnt} = $#configs + 1;
0721        for my $config (@configs) {
0722                $$pn_arg_ref{config} = $config;
0723                $lines_printed += &print_node($pn_arg_ref);
0724        }
0725 
0726        return $lines_printed;
0727 }
0728 
0729 
0730 sub handle_compatible()
0731 {
0732        my $full_node     = shift;
0733        my $node          = shift;
0734        my $compatible    = shift;
0735        my $node_enabled  = shift;
0736 
0737        my $compat;
0738        my $lines_printed = 0;
0739        my %pn_arg        = ();
0740 
0741        return if (!$node or !$compatible);
0742 
0743        # Do not process compatible property of root node,
0744        # it is used to match board, not to bind a driver.
0745        return if ($node eq "/");
0746 
0747        $pn_arg{full_node}    = $full_node;
0748        $pn_arg{node}         = $node;
0749        $pn_arg{node_enabled} = $node_enabled;
0750 
0751        my @compatibles = split('", "', $compatible);
0752 
0753        $compatibles[0] =~ s/^"//;
0754        $compatibles[$#compatibles] =~ s/"$//;
0755 
0756        $pn_arg{compatible_cnt} = $#compatibles + 1;
0757 
0758        COMPAT:
0759        for $compat (@compatibles) {
0760 
0761                $pn_arg{compat}     = $compat;
0762                $pn_arg{driver_cnt} = 0;
0763                $pn_arg{white_list} = 0;
0764 
0765                if (exists($compat_white_list{$compat})) {
0766                        $pn_arg{white_list} = 1;
0767                        $pn_arg{driver}     = "no_driver";
0768                        $pn_arg{config_cnt} = 1;
0769                        $pn_arg{config}     = "no_config";
0770                        $lines_printed += &print_node(\%pn_arg);
0771                        next COMPAT;
0772                }
0773 
0774                # ----- if compat previously seen, use cached info
0775 
0776                if (exists($compat_driver{$compat})) {
0777                        for my $driver (@{ $compat_driver{$compat} }) {
0778                                $pn_arg{driver}     = $driver;
0779                                $pn_arg{driver_cnt} = $driver_count{$compat};
0780                                $pn_arg{config_cnt} = $#{ $driver_config{$driver}} + 1;
0781 
0782                                for my $config (@{ $driver_config{$driver} }) {
0783                                        $pn_arg{config} = $config;
0784                                        $lines_printed += &print_node(\%pn_arg);
0785                                }
0786 
0787                                if (!@{ $driver_config{$driver} }) {
0788                                        # no config cached yet
0789                                        # $driver in %driver_hard_code_list
0790                                        # but not %driver_config_hard_code_list
0791                                        $lines_printed += &find_kconfig(\%pn_arg, $driver);
0792                                }
0793                        }
0794                        next COMPAT;
0795                }
0796 
0797 
0798                # ----- Find drivers (source files that contain compatible)
0799 
0800                # this will miss arch/sparc/include/asm/parport.h
0801                # It is better to move the compatible out of the .h
0802                # than to add *.h. to the files list, because *.h generates
0803                # a lot of false negatives.
0804                my $files = '"*.c"';
0805                my $drivers = `git grep -l '"$compat"' -- $files`;
0806                chomp($drivers);
0807                if ($drivers eq "") {
0808                        $pn_arg{driver} = "no_driver";
0809                        $pn_arg{config_cnt} = 1;
0810                        $pn_arg{config} = "no_config";
0811                        push @{ $compat_driver{$compat} }, "no_driver";
0812                        $lines_printed += &print_node(\%pn_arg);
0813                        next COMPAT;
0814                }
0815 
0816                my @drivers = split("\n", $drivers);
0817                $driver_count{$compat} = $#drivers + 1;
0818                $pn_arg{driver_cnt}    = $#drivers + 1;
0819 
0820                DRIVER:
0821                for my $driver (@drivers) {
0822                        push @{ $compat_driver{$compat} }, $driver;
0823                        $pn_arg{driver} = $driver;
0824 
0825                        # ----- if driver previously seen, use cached info
0826 
0827                        $pn_arg{config_cnt} = $#{ $driver_config{$driver} } + 1;
0828                        for my $config (@{ $driver_config{$driver} }) {
0829                                $pn_arg{config} = $config;
0830                                $lines_printed += &print_node(\%pn_arg);
0831                        }
0832                        if (@{ $driver_config{$driver} }) {
0833                                next DRIVER;
0834                        }
0835 
0836                        if ($black_list_driver) {
0837                                for $black (@black_list_driver) {
0838                                        next DRIVER if ($driver =~ /^$black$/);
0839                                }
0840                        }
0841 
0842 
0843                        # ----- Find Kconfig symbols that enable driver
0844 
0845                        $lines_printed += &find_kconfig(\%pn_arg, $driver);
0846 
0847                }
0848        }
0849 
0850        # White space (line) between nodes for readability.
0851        # Each node may report several compatibles.
0852        # For each compatible, multiple drivers may be reported.
0853        # For each driver, multiple CONFIG_ options may be reported.
0854        if ($lines_printed) {
0855                print "\n";
0856        }
0857 }
0858 
0859 sub read_dts()
0860 {
0861        my $file         = shift;
0862 
0863        my $compatible   = "";
0864        my $line;
0865        my $node         = "";
0866        my $node_enabled = "";
0867 
0868        if (! -r $file) {
0869                print STDERR "file '$file' is not readable or does not exist\n";
0870                exit 3;
0871        }
0872 
0873        if (!open(DT_FILE, "-|", "$dtx_diff $file")) {
0874                print STDERR "\n";
0875                print STDERR "shell command failed:\n";
0876                print STDERR "   $dtx_diff $file\n";
0877                print STDERR "\n";
0878                exit 3;
0879        }
0880 
0881        FILE:
0882        while ($line = <DT_FILE>) {
0883                chomp($line);
0884 
0885                if ($line =~ /{/) {
0886 
0887                        &handle_compatible($full_node, $node, $compatible,
0888                                           $node_enabled);
0889 
0890                        while ($end_node_count-- > 0) {
0891                                pop @full_node;
0892                        };
0893                        $end_node_count = 0;
0894                        $full_node = @full_node[-1];
0895 
0896                        $node = $line;
0897                        $node =~ s/^\s*(.*)\s+\{.*/$1/;
0898                        $node =~ s/.*: //;
0899                        if ($node eq '/' ) {
0900                                $full_node = '/';
0901                        } elsif ($full_node ne '/') {
0902                                $full_node = $full_node . '/' . $node;
0903                        } else {
0904                                $full_node = '/' . $node;
0905                        }
0906                        push @full_node, $full_node;
0907 
0908                        $compatible = "";
0909                        $node_enabled = "";
0910                        next FILE;
0911                }
0912 
0913                if ($line =~ /}/) {
0914                        $end_node_count++;
0915                }
0916 
0917                if ($line =~ /(\s+|^)status =/) {
0918                        $node_enabled = $line;
0919                        $node_enabled =~ s/^\t*//;
0920                        $node_enabled =~ s/^status = "//;
0921                        $node_enabled =~ s/";$//;
0922                        next FILE;
0923                }
0924 
0925                if ($line =~ /(\s+|^)compatible =/) {
0926                        # Extract all compatible entries for this device
0927                        # White space matching here and in handle_compatible() is
0928                        # precise, because input format is the output of dtc,
0929                        # which is invoked by dtx_diff.
0930                        $compatible = $line;
0931                        $compatible =~ s/^\t*//;
0932                        $compatible =~ s/^compatible = //;
0933                        $compatible =~ s/;$//;
0934                }
0935        }
0936 
0937        &handle_compatible($full_node, $node, $compatible, $node_enabled);
0938 
0939        close(DT_FILE);
0940 }
0941 
0942 
0943 sub read_config_file()
0944 {
0945        if (! -r $config_file) {
0946                print STDERR "file '$config_file' is not readable or does not exist\n";
0947                exit 2;
0948        }
0949 
0950        if (!open(CONFIG_FILE, "<", "$config_file")) {
0951                print STDERR "open $config_file failed\n";
0952                exit 2;
0953        }
0954 
0955        my @line;
0956 
0957        LINE:
0958        while ($line = <CONFIG_FILE>) {
0959                chomp($line);
0960                next LINE if ($line =~ /^\s*#/);
0961                next LINE if ($line =~ /^\s*$/);
0962                @line = split /=/, $line;
0963                $existing_config{@line[0]} = @line[1];
0964        }
0965 
0966        close(CONFIG_FILE);
0967 }
0968 
0969 
0970 sub cmd_line_err()
0971 {
0972        my $msg = shift;
0973 
0974        print STDERR "\n";
0975        print STDERR "   ERROR processing command line options\n";
0976        print STDERR "         $msg\n" if ($msg ne "");
0977        print STDERR "\n";
0978        print STDERR "   For help, type '$script_name --help'\n";
0979        print STDERR "\n";
0980 }
0981 
0982 
0983 # -----------------------------------------------------------------------------
0984 # program entry point
0985 
0986 Getopt::Long::Configure("no_ignore_case", "bundling");
0987 
0988 if (!GetOptions(
0989        "c=s"               => \$config_file,
0990        "config=s"          => \$config_file,
0991        "config-format"     => \$config_format,
0992        "exclude-flag=s"    => \@exclude_flag,
0993        "h"                 => \$help,
0994        "help"              => \$help,
0995        "black-list-driver" => \$black_list_driver,
0996        "white-list-config" => \$white_list_config,
0997        "white-list-driver" => \$white_list_driver,
0998        "include-flag=s"    => \@include_flag,
0999        "include-suspect"   => \$include_suspect,
1000        "short-name"        => \$short_name,
1001        "show-lists"        => \$show_lists,
1002        "version"           => \$version,
1003        )) {
1004 
1005        &cmd_line_err();
1006 
1007        exit 1;
1008 }
1009 
1010 
1011 my $exit_after_messages = 0;
1012 
1013 if ($version) {
1014        print STDERR "\n$script_name  $VUFX\n\n";
1015        $exit_after_messages = 1;
1016 }
1017 
1018 
1019 if ($help) {
1020        &usage;
1021        $exit_after_messages = 1;
1022 }
1023 
1024 
1025 if ($show_lists) {
1026 
1027        print "\n";
1028        print "These compatibles are hard coded to have no driver.\n";
1029        print "\n";
1030        for my $compat (sort keys %compat_white_list) {
1031                print "   $compat\n";
1032        }
1033 
1034 
1035        print "\n\n";
1036        print "The driver for these compatibles is hard coded (white list).\n";
1037        print "\n";
1038        my $max_compat_len = 0;
1039        for my $compat (sort keys %driver_hard_code_list) {
1040                if (length $compat > $max_compat_len) {
1041                        $max_compat_len = length $compat;
1042                }
1043        }
1044        for my $compat (sort keys %driver_hard_code_list) {
1045                if (($driver ne "hardcoded_no_driver") && ($driver ne "no_driver")) {
1046                        my $first = 1;
1047                        for my $driver (@{ $driver_hard_code_list{$compat} }) {
1048                                if ($first) {
1049                                        print "   $compat";
1050                                        print " " x ($max_compat_len - length $compat);
1051                                        $first = 0;
1052                                } else {
1053                                        print "   ", " " x $max_compat_len;
1054                                }
1055                                print "  $driver\n";
1056                        }
1057                }
1058        }
1059 
1060 
1061        print "\n\n";
1062        print "The configuration option for these drivers is hard coded (white list).\n";
1063        print "\n";
1064        my $max_driver_len = 0;
1065        for my $driver (sort keys %driver_config_hard_code_list) {
1066                if (length $driver > $max_driver_len) {
1067                        $max_driver_len = length $driver;
1068                }
1069        }
1070        for my $driver (sort keys %driver_config_hard_code_list) {
1071                if (($driver ne "hardcoded_no_driver") && ($driver ne "no_driver")) {
1072                        my $first = 1;
1073                        for my $config (@{ $driver_config_hard_code_list{$driver} }) {
1074                                if ($first) {
1075                                        print "   $driver";
1076                                        print " " x ($max_driver_len - length $driver);
1077                                        $first = 0;
1078                                } else {
1079                                        print "   ", " " x $max_driver_len;
1080                                }
1081                                print "  $config\n";
1082                        }
1083                }
1084        }
1085 
1086 
1087        print "\n\n";
1088        print "These drivers are black listed.\n";
1089        print "\n";
1090        for my $driver (@black_list_driver) {
1091                print "   $driver\n";
1092        }
1093 
1094        print "\n";
1095 
1096        $exit_after_messages = 1;
1097 }
1098 
1099 
1100 if ($exit_after_messages) {
1101        exit 0;
1102 }
1103 
1104 
1105 $exclude_flag_pattern = "[";
1106 for my $exclude_flag (@exclude_flag) {
1107        $exclude_flag_pattern = $exclude_flag_pattern . $exclude_flag;
1108 }
1109 $exclude_flag_pattern = $exclude_flag_pattern . "]";
1110 # clean up if empty
1111 $exclude_flag_pattern =~ s/^\[\]$//;
1112 
1113 
1114 $include_flag_pattern = "[";
1115 for my $include_flag (@include_flag) {
1116        $include_flag_pattern = $include_flag_pattern . $include_flag;
1117 }
1118 $include_flag_pattern = $include_flag_pattern . "]";
1119 # clean up if empty
1120 $include_flag_pattern =~ s/^\[\]$//;
1121 
1122 
1123 if ($exclude_flag_pattern) {
1124        my $found = 0;
1125        for $pr_flag_value (@pr_flag_value) {
1126                if ($exclude_flag_pattern =~ m/$pr_flag_value/) {
1127                        $found = 1;
1128                }
1129        }
1130        if (!$found) {
1131                &cmd_line_err("invalid value for FLAG in --exclude-flag\n");
1132                exit 1
1133        }
1134 }
1135 
1136 if ($include_flag_pattern) {
1137        my $found = 0;
1138        for $pr_flag_value (@pr_flag_value) {
1139                if ($include_flag_pattern =~ m/$pr_flag_value/) {
1140                        $found = 1;
1141                }
1142        }
1143        if (!$found) {
1144                &cmd_line_err("invalid value for FLAG in --include-flag\n");
1145                exit 1
1146        }
1147 }
1148 
1149 if ($include_suspect) {
1150        $include_flag_pattern =~ s/\[//;
1151        $include_flag_pattern =~ s/\]//;
1152        $include_flag_pattern = "[" . $include_flag_pattern . "A-Z]";
1153 }
1154 
1155 if ($exclude_flag_pattern =~ m/$include_flag_pattern/) {
1156        &cmd_line_err("the same flag appears in both --exclude-flag and --include-flag or --include-suspect\n");
1157        exit 1
1158 }
1159 
1160 
1161 # ($#ARGV < 0) is valid for --help, --version
1162 if ($#ARGV < 0) {
1163        &cmd_line_err("device-tree... is required");
1164        exit 1
1165 }
1166 
1167 
1168 if ($config_file) {
1169        &read_config_file();
1170 }
1171 
1172 
1173 # avoid pushing duplicates for this value
1174 $driver = "hardcoded_no_driver";
1175 for $config ( @{ $driver_config_hard_code_list{$driver} } ) {
1176        push @{ $driver_config{$driver} }, $config;
1177 }
1178 
1179 if ($white_list_driver) {
1180        for my $compat (keys %driver_hard_code_list) {
1181                for my $driver (@{ $driver_hard_code_list{$compat} }) {
1182                        push @{ $compat_driver{$compat} }, $driver;
1183                        if ($driver ne "hardcoded_no_driver") {
1184                                $driver_count{$compat} = scalar @{ $compat_driver{$compat} };
1185                        }
1186                }
1187        }
1188 }
1189 
1190 if ($white_list_config) {
1191        for my $driver (keys %driver_config_hard_code_list) {
1192                if ($driver ne "hardcoded_no_driver") {
1193                        for $config ( @{ $driver_config_hard_code_list{$driver} } ) {
1194                                push @{ $driver_config{$driver} }, $config;
1195                        }
1196                }
1197        }
1198 }
1199 
1200 if (-x "scripts/dtc/dtx_diff") {
1201        $dtx_diff = "scripts/dtc/dtx_diff";
1202 } else {
1203 
1204        print STDERR "\n";
1205        print STDERR "$script_name must be run from the root directory of a Linux kernel tree\n";
1206        print STDERR "\n";
1207        exit 3;
1208 }
1209 
1210 for $file (@ARGV) {
1211        &read_dts($file);
1212 }