#!/usr/bin/env perl 
 | 
# SPDX-License-Identifier: GPL-2.0-only 
 | 
  
 | 
# Copyright 2016 by Frank Rowand 
 | 
# Copyright 2016 by Gaurav Minocha 
 | 
# 
 | 
  
 | 
use strict 'refs'; 
 | 
use strict subs; 
 | 
  
 | 
use Getopt::Long; 
 | 
  
 | 
$VUFX = "160610a"; 
 | 
  
 | 
$script_name = $0; 
 | 
$script_name =~ s|^.*/||; 
 | 
  
 | 
  
 | 
# ----- constants for print_flags() 
 | 
  
 | 
# Position in string $pr_flags.  Range of 0..($num_pr_flags - 1). 
 | 
$pr_flag_pos_mcompatible       = 0; 
 | 
$pr_flag_pos_driver            = 1; 
 | 
$pr_flag_pos_mdriver           = 2; 
 | 
$pr_flag_pos_config            = 3; 
 | 
$pr_flag_pos_mconfig           = 4; 
 | 
$pr_flag_pos_node_not_enabled  = 5; 
 | 
$pr_flag_pos_white_list        = 6; 
 | 
$pr_flag_pos_hard_coded        = 7; 
 | 
$pr_flag_pos_config_hard_coded = 8; 
 | 
$pr_flag_pos_config_none       = 9; 
 | 
$pr_flag_pos_config_m          = 10; 
 | 
$pr_flag_pos_config_y          = 11; 
 | 
$pr_flag_pos_config_test_fail  = 12; 
 | 
  
 | 
$num_pr_flags = $pr_flag_pos_config_test_fail + 1; 
 | 
  
 | 
# flags in @pr_flag_value must be unique values to allow simple regular 
 | 
# expessions to work for --include_flags and --exclude_flags. 
 | 
# Convention: use upper case letters for potential issues or problems. 
 | 
  
 | 
@pr_flag_value = ('M', 'd', 'D', 'c', 'C', 'E', 'W', 'H', 'x', 'n', 'm', 'y', 'F'); 
 | 
  
 | 
@pr_flag_help = ( 
 | 
    "multiple compatibles found for this node", 
 | 
    "driver found for this compatible", 
 | 
    "multiple drivers found for this compatible", 
 | 
    "kernel config found for this driver", 
 | 
    "multiple config options found for this driver", 
 | 
    "node is not enabled", 
 | 
    "compatible is white listed", 
 | 
    "matching driver and/or kernel config is hard coded", 
 | 
    "kernel config hard coded in Makefile", 
 | 
    "one or more kernel config file options is not set", 
 | 
    "one or more kernel config file options is set to 'm'", 
 | 
    "one or more kernel config file options is set to 'y'", 
 | 
    "one of more kernel config file options fails to have correct value" 
 | 
); 
 | 
  
 | 
  
 | 
# ----- 
 | 
  
 | 
%driver_config = ();   # driver config array, indexed by driver source file 
 | 
%driver_count = ();    # driver_cnt, indexed by compatible 
 | 
%compat_driver = ();   # compatible driver array, indexed by compatible 
 | 
%existing_config = (); # existing config symbols present in given config file 
 | 
                       # expected values are: "y", "m", a decimal number, a 
 | 
                       # hex number, or a string 
 | 
  
 | 
# ----- magic compatibles, do not have a driver 
 | 
# 
 | 
# Will not search for drivers for these compatibles. 
 | 
  
 | 
%compat_white_list = ( 
 | 
       'none'                  => '1', 
 | 
       'pci'                   => '1', 
 | 
       'simple-bus'            => '1', 
 | 
); 
 | 
  
 | 
# Will not search for drivers for these compatibles. 
 | 
# 
 | 
# These compatibles have a very large number of false positives. 
 | 
# 
 | 
# 'hardcoded_no_driver' is a magic value.  Other code knows this 
 | 
# magic value.  Do not use 'no_driver' here! 
 | 
# 
 | 
# Revisit each 'hardcoded_no_driver' to see how the compatible 
 | 
# is used.  Are there drivers that can be provided? 
 | 
  
 | 
%driver_hard_code_list = ( 
 | 
       'cache'                 => ['hardcoded_no_driver'], 
 | 
       'eeprom'                => ['hardcoded_no_driver'], 
 | 
       'gpio'                  => ['hardcoded_no_driver'], 
 | 
       'gpio-keys'             => ['drivers/input/keyboard/gpio_keys.c'], 
 | 
       'i2c-gpio'              => ['drivers/i2c/busses/i2c-gpio.c'], 
 | 
       'isa'                   => ['arch/mips/mti-malta/malta-dt.c', 
 | 
                                    'arch/x86/kernel/devicetree.c'], 
 | 
       'led'                   => ['hardcoded_no_driver'], 
 | 
       'm25p32'                => ['hardcoded_no_driver'], 
 | 
       'm25p64'                => ['hardcoded_no_driver'], 
 | 
       'm25p80'                => ['hardcoded_no_driver'], 
 | 
       'mtd-ram'               => ['drivers/mtd/maps/physmap_of.c'], 
 | 
       'pwm-backlight'         => ['drivers/video/backlight/pwm_bl.c'], 
 | 
       'spidev'                => ['hardcoded_no_driver'], 
 | 
       'syscon'                => ['drivers/mfd/syscon.c'], 
 | 
       'tlv320aic23'           => ['hardcoded_no_driver'], 
 | 
       'wm8731'                => ['hardcoded_no_driver'], 
 | 
); 
 | 
  
 | 
# Use these config options instead of searching makefiles 
 | 
  
 | 
%driver_config_hard_code_list = ( 
 | 
  
 | 
       # this one needed even if %driver_hard_code_list is empty 
 | 
       'no_driver'                             => ['no_config'], 
 | 
       'hardcoded_no_driver'                   => ['no_config'], 
 | 
  
 | 
       # drivers/usb/host/ehci-ppc-of.c 
 | 
       # drivers/usb/host/ehci-xilinx-of.c 
 | 
       #  are included from: 
 | 
       #    drivers/usb/host/ehci-hcd.c 
 | 
       #  thus the search of Makefile for the included .c files is incorrect 
 | 
       # ehci-hcd.c wraps the includes with ifdef CONFIG_USB_EHCI_HCD_..._OF 
 | 
       # 
 | 
       # similar model for ohci-hcd.c (but no ohci-xilinx-of.c) 
 | 
       # 
 | 
       # similarly, uhci-hcd.c includes uhci-platform.c 
 | 
  
 | 
       'drivers/usb/host/ehci-ppc-of.c'        => ['CONFIG_USB_EHCI_HCD', 
 | 
                                                   'CONFIG_USB_EHCI_HCD_PPC_OF'], 
 | 
       'drivers/usb/host/ohci-ppc-of.c'        => ['CONFIG_USB_OHCI_HCD', 
 | 
                                                   'CONFIG_USB_OHCI_HCD_PPC_OF'], 
 | 
  
 | 
       'drivers/usb/host/ehci-xilinx-of.c'     => ['CONFIG_USB_EHCI_HCD', 
 | 
                                                   'CONFIG_USB_EHCI_HCD_XILINX'], 
 | 
  
 | 
       'drivers/usb/host/uhci-platform.c'      => ['CONFIG_USB_UHCI_HCD', 
 | 
                                                   'CONFIG_USB_UHCI_PLATFORM'], 
 | 
  
 | 
       # scan_makefile will find only one of these config options: 
 | 
       #    ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),) 
 | 
       'arch/arm/mach-imx/platsmp.c'           => ['CONFIG_SOC_IMX6 && CONFIG_SMP', 
 | 
                                                   'CONFIG_SOC_LS1021A && CONFIG_SMP'], 
 | 
); 
 | 
  
 | 
  
 | 
# 'virt/kvm/arm/.*' are controlled by makefiles in other directories, 
 | 
# using relative paths, such as 'KVM := ../../../virt/kvm'.  Do not 
 | 
# add complexity to find_kconfig() to deal with this.  There is a long 
 | 
# term intent to change the kvm related makefiles to the normal kernel 
 | 
# style.  After that is done, this entry can be removed from the 
 | 
# black_list_driver. 
 | 
  
 | 
@black_list_driver = ( 
 | 
       # kvm no longer a problem after commit 503a62862e8f in 4.7-rc1 
 | 
       # 'virt/kvm/arm/.*', 
 | 
); 
 | 
  
 | 
  
 | 
sub usage() 
 | 
{ 
 | 
       print 
 | 
" 
 | 
Usage: $script_name [options] device-tree... 
 | 
  
 | 
    device_tree is: dts_file | dtb_file | proc_device-tree 
 | 
  
 | 
  
 | 
Valid options: 
 | 
     -c FILE             Read kernel config options from FILE 
 | 
    --config FILE        synonym for 'c' 
 | 
    --config-format      config file friendly output format 
 | 
    --exclude-flag FLAG  exclude entries with a matching flag 
 | 
     -h                  Display this message and exit 
 | 
    --help               synonym for 'h' 
 | 
    --black-list-driver  use driver black list 
 | 
    --white-list-config  use config white list 
 | 
    --white-list-driver  use driver white list 
 | 
    --include-flag FLAG  include only entries with a matching flag 
 | 
    --include-suspect    include only entries with an uppercase flag 
 | 
    --short-name         do not show the path portion of the node name 
 | 
    --show-lists         report of white and black lists 
 | 
    --version            Display program version and exit 
 | 
  
 | 
  
 | 
  Report driver source files that match the compatibles in the device 
 | 
  tree file and the kernel config options that enable the driver source 
 | 
  files. 
 | 
  
 | 
  This program must be run in the root directory of a Linux kernel 
 | 
  source tree. 
 | 
  
 | 
  The default format is a report that is intended to be easily human 
 | 
  scannable. 
 | 
  
 | 
  An alternate format can be selected by --config-format.  This will 
 | 
  create output that can easily be edited to create a fragment that can 
 | 
  be appended to the existing kernel config file.  Each entry consists of 
 | 
  multiple lines.  The first line reports flags, the node path, compatible 
 | 
  value, driver file matching the compatible, configuration options, and 
 | 
  current values of the configuration options.  For each configuration 
 | 
  option, the following lines report the current value and the value that 
 | 
  is required for the driver file to be included in the kernel. 
 | 
  
 | 
  If a large number of drivers or config options is listed for a node, 
 | 
  and the '$pr_flag_value[$pr_flag_pos_hard_coded]' flag is set consider using --white-list-config and/or 
 | 
  --white-list-driver.  If the white list option suppresses the correct 
 | 
  entry please report that as a bug. 
 | 
  
 | 
  CAUTION: 
 | 
     This program uses heuristics to guess which driver(s) support each 
 | 
     compatible string and which config option(s) enables the driver(s). 
 | 
     Do not believe that the reported information is fully correct. 
 | 
     This program is intended to aid the process of determining the 
 | 
     proper kernel configuration for a device tree, but this is not 
 | 
     a fully automated process -- human involvement may still be 
 | 
     required! 
 | 
  
 | 
     The driver match heuristic used is to search for source files 
 | 
     containing the compatible string enclosed in quotes. 
 | 
  
 | 
     This program might not be able to find all drivers matching a 
 | 
     compatible string. 
 | 
  
 | 
     Some makefiles are overly clever.  This program was not made 
 | 
     complex enough to handle them.  If no config option is listed 
 | 
     for a driver, look at the makefile for the driver source file. 
 | 
     Even if a config option is listed for a driver, some other 
 | 
     available config options may not be listed. 
 | 
  
 | 
  FLAG values: 
 | 
"; 
 | 
  
 | 
       for ($k = 0; $k < $num_pr_flags; $k++) { 
 | 
               printf "     %s   %s\n", $pr_flag_value[$k], $pr_flag_help[$k]; 
 | 
       } 
 | 
  
 | 
       print 
 | 
" 
 | 
     Upper case letters indicate potential issues or problems. 
 | 
  
 | 
  The flag: 
 | 
  
 | 
"; 
 | 
  
 | 
       $k = $pr_flag_pos_hard_coded; 
 | 
       printf "     %s   %s\n", $pr_flag_value[$k], $pr_flag_help[$k]; 
 | 
  
 | 
       print 
 | 
" 
 | 
  will be set if the config or driver is in the white lists, even if 
 | 
  --white-list-config and --white-list-driver are not specified. 
 | 
  This is a hint that 1) many of these reported lines are likely to 
 | 
  be incorrect, and 2) using those options will reduce the number of 
 | 
  drivers and/or config options reported. 
 | 
  
 | 
  --white-list-config and --white-list-driver may not be accurate if this 
 | 
  program is not well maintained.  Use them with appropriate skepticism. 
 | 
  Use the --show-lists option to report the values in the list. 
 | 
  
 | 
  Return value: 
 | 
    0   if no error 
 | 
    1   error processing command line 
 | 
    2   unable to open or read kernel config file 
 | 
    3   unable to open or process input device tree file(s) 
 | 
  
 | 
  EXAMPLES: 
 | 
  
 | 
     dt_to_config arch/arm/boot/dts/my_dts_file.dts 
 | 
  
 | 
       Basic report. 
 | 
  
 | 
     dt_to_config \\ 
 | 
        --config \${KBUILD_OUTPUT}/.config \\ 
 | 
        arch/\${ARCH}/boot/dts/my_dts_file.dts 
 | 
  
 | 
       Full report, with config file issues noted. 
 | 
  
 | 
     dt_to_config --include-suspect \\ 
 | 
        --config \${KBUILD_OUTPUT}/.config \\ 
 | 
        arch/\${ARCH}/boot/dts/my_dts_file.dts 
 | 
  
 | 
       Report of node / compatible string / driver tuples that should 
 | 
       be further investigated.  A node may have multiple compatible 
 | 
       strings.  A compatible string may be matched by multiple drivers. 
 | 
       A driver may have config file issues noted.  The compatible string 
 | 
       and/or driver may be in the white lists. 
 | 
  
 | 
     dt_to_config --include-suspect --config-format \\ 
 | 
        --config ${KBUILD_OUTPUT}/.config \\ 
 | 
        arch/\${ARCH}/boot/dts/my_dts_file.dts 
 | 
  
 | 
       Report of node / compatible string / driver tuples that should 
 | 
       be further investigated.  The report can be edited to uncomment 
 | 
       the config options to select the desired tuple for a given node. 
 | 
       A node may have multiple compatible strings.  A compatible string 
 | 
       may be matched by multiple drivers.  A driver may have config file 
 | 
       issues noted.  The compatible string and/or driver may be in the 
 | 
       white lists. 
 | 
  
 | 
"; 
 | 
} 
 | 
  
 | 
sub set_flag() 
 | 
{ 
 | 
       # pr_flags_ref is a reference to $pr_flags 
 | 
  
 | 
       my $pr_flags_ref = shift; 
 | 
       my $pos          = shift; 
 | 
  
 | 
       substr $$pr_flags_ref, $pos, 1, $pr_flag_value[$pos]; 
 | 
  
 | 
       return $pr_flags; 
 | 
} 
 | 
  
 | 
sub print_flags() 
 | 
{ 
 | 
       # return 1 if anything printed, else 0 
 | 
  
 | 
       # some fields of pn_arg_ref might not be used in this function, but 
 | 
       # extract all of them anyway. 
 | 
       my $pn_arg_ref     = shift; 
 | 
  
 | 
       my $compat         = $pn_arg_ref->{compat}; 
 | 
       my $compatible_cnt = $pn_arg_ref->{compatible_cnt}; 
 | 
       my $config         = $pn_arg_ref->{config}; 
 | 
       my $config_cnt     = $pn_arg_ref->{config_cnt}; 
 | 
       my $driver         = $pn_arg_ref->{driver}; 
 | 
       my $driver_cnt     = $pn_arg_ref->{driver_cnt}; 
 | 
       my $full_node      = $pn_arg_ref->{full_node}; 
 | 
       my $node           = $pn_arg_ref->{node}; 
 | 
       my $node_enabled   = $pn_arg_ref->{node_enabled}; 
 | 
       my $white_list     = $pn_arg_ref->{white_list}; 
 | 
  
 | 
       my $pr_flags       = '-' x $num_pr_flags; 
 | 
  
 | 
  
 | 
       # ----- set flags in $pr_flags 
 | 
  
 | 
       if ($compatible_cnt > 1) { 
 | 
               &set_flag(\$pr_flags, $pr_flag_pos_mcompatible); 
 | 
       } 
 | 
  
 | 
       if ($config_cnt > 1) { 
 | 
               &set_flag(\$pr_flags, $pr_flag_pos_mconfig); 
 | 
       } 
 | 
  
 | 
       if ($driver_cnt >= 1) { 
 | 
               &set_flag(\$pr_flags, $pr_flag_pos_driver); 
 | 
       } 
 | 
  
 | 
       if ($driver_cnt > 1) { 
 | 
               &set_flag(\$pr_flags, $pr_flag_pos_mdriver); 
 | 
       } 
 | 
  
 | 
       # These strings are the same way the linux kernel tests. 
 | 
       # The ePapr lists of values is slightly different. 
 | 
       if (!( 
 | 
             ($node_enabled eq "") || 
 | 
             ($node_enabled eq "ok") || 
 | 
             ($node_enabled eq "okay") 
 | 
            )) { 
 | 
               &set_flag(\$pr_flags, $pr_flag_pos_node_not_enabled); 
 | 
       } 
 | 
  
 | 
       if ($white_list) { 
 | 
               &set_flag(\$pr_flags, $pr_flag_pos_white_list); 
 | 
       } 
 | 
  
 | 
       if (exists($driver_hard_code_list{$compat}) || 
 | 
           (exists($driver_config_hard_code_list{$driver}) && 
 | 
            ($driver ne "no_driver"))) { 
 | 
               &set_flag(\$pr_flags, $pr_flag_pos_hard_coded); 
 | 
       } 
 | 
  
 | 
       my @configs = split(' && ', $config); 
 | 
       for $configs (@configs) { 
 | 
               $not = $configs =~ /^!/; 
 | 
               $configs =~ s/^!//; 
 | 
  
 | 
               if (($configs ne "no_config") && ($configs ne "no_makefile")) { 
 | 
                       &set_flag(\$pr_flags, $pr_flag_pos_config); 
 | 
               } 
 | 
  
 | 
               if (($config_cnt >= 1) && 
 | 
                   ($configs !~ /CONFIG_/) && 
 | 
                   (($configs ne "no_config") && ($configs ne "no_makefile"))) { 
 | 
                       &set_flag(\$pr_flags, $pr_flag_pos_config_hard_coded); 
 | 
               } 
 | 
  
 | 
               my $existing_config = $existing_config{$configs}; 
 | 
               if ($existing_config eq "m") { 
 | 
                       &set_flag(\$pr_flags, $pr_flag_pos_config_m); 
 | 
                       # Possible fail, depends on whether built in or 
 | 
                       # module is desired. 
 | 
                       &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail); 
 | 
               } elsif ($existing_config eq "y") { 
 | 
                       &set_flag(\$pr_flags, $pr_flag_pos_config_y); 
 | 
                       if ($not) { 
 | 
                               &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail); 
 | 
                       } 
 | 
               } elsif (($config_file) && ($configs =~ /CONFIG_/)) { 
 | 
                       &set_flag(\$pr_flags, $pr_flag_pos_config_none); 
 | 
                       if (!$not) { 
 | 
                               &set_flag(\$pr_flags, $pr_flag_pos_config_test_fail); 
 | 
                       } 
 | 
               } 
 | 
       } 
 | 
  
 | 
       # ----- include / exclude filters 
 | 
  
 | 
       if ($include_flag_pattern && ($pr_flags !~ m/$include_flag_pattern/)) { 
 | 
               return 0; 
 | 
       } 
 | 
  
 | 
       if ($exclude_flag_pattern && ($pr_flags =~ m/$exclude_flag_pattern/)) { 
 | 
               return 0; 
 | 
       } 
 | 
  
 | 
       if ($config_format) { 
 | 
               print "# "; 
 | 
       } 
 | 
       print "$pr_flags : "; 
 | 
  
 | 
       return 1; 
 | 
} 
 | 
  
 | 
  
 | 
sub print_node() 
 | 
{ 
 | 
       # return number of lines printed 
 | 
  
 | 
       # some fields of pn_arg_ref might not be used in this function, but 
 | 
       # extract all of them anyway. 
 | 
       my $pn_arg_ref     = shift; 
 | 
  
 | 
       my $compat         = $pn_arg_ref->{compat}; 
 | 
       my $compatible_cnt = $pn_arg_ref->{compatible_cnt}; 
 | 
       my $config         = $pn_arg_ref->{config}; 
 | 
       my $config_cnt     = $pn_arg_ref->{config_cnt}; 
 | 
       my $driver         = $pn_arg_ref->{driver}; 
 | 
       my $driver_cnt     = $pn_arg_ref->{driver_cnt}; 
 | 
       my $full_node      = $pn_arg_ref->{full_node}; 
 | 
       my $node           = $pn_arg_ref->{node}; 
 | 
       my $node_enabled   = $pn_arg_ref->{node_enabled}; 
 | 
       my $white_list     = $pn_arg_ref->{white_list}; 
 | 
  
 | 
       my $separator; 
 | 
  
 | 
       if (! &print_flags($pn_arg_ref)) { 
 | 
               return 0; 
 | 
       } 
 | 
  
 | 
  
 | 
       if ($short_name) { 
 | 
               print "$node"; 
 | 
       } else { 
 | 
               print "$full_node"; 
 | 
       } 
 | 
       print " : $compat : $driver : $config : "; 
 | 
  
 | 
       my @configs = split(' && ', $config); 
 | 
  
 | 
       if ($config_file) { 
 | 
               for $configs (@configs) { 
 | 
                       $configs =~ s/^!//; 
 | 
                       my $existing_config = $existing_config{$configs}; 
 | 
                       if (!$existing_config) { 
 | 
                               # check for /-m/, /-y/, or /-objs/ 
 | 
                               if ($configs !~ /CONFIG_/) { 
 | 
                                       $existing_config = "x"; 
 | 
                               }; 
 | 
                       }; 
 | 
                       if ($existing_config) { 
 | 
                               print "$separator", "$existing_config"; 
 | 
                               $separator = ", "; 
 | 
                       } else { 
 | 
                               print "$separator", "n"; 
 | 
                               $separator = ", "; 
 | 
                       } 
 | 
               } 
 | 
       } else { 
 | 
               print "none"; 
 | 
       } 
 | 
  
 | 
       print "\n"; 
 | 
  
 | 
       if ($config_format) { 
 | 
               for $configs (@configs) { 
 | 
                       $not = $configs =~ /^!/; 
 | 
                       $configs =~ s/^!//; 
 | 
                       my $existing_config = $existing_config{$configs}; 
 | 
  
 | 
                       if ($not) { 
 | 
                               if ($configs !~ /CONFIG_/) { 
 | 
                                       print "# $configs\n"; 
 | 
                               } elsif ($existing_config eq "m") { 
 | 
                                       print "# $configs is m\n"; 
 | 
                                       print "# $configs=n\n"; 
 | 
                               } elsif ($existing_config eq "y") { 
 | 
                                       print "# $configs is set\n"; 
 | 
                                       print "# $configs=n\n"; 
 | 
                               } else { 
 | 
                                       print "# $configs is not set\n"; 
 | 
                                       print "# $configs=n\n"; 
 | 
                               } 
 | 
  
 | 
                       } else { 
 | 
                               if ($configs !~ /CONFIG_/) { 
 | 
                                       print "# $configs\n"; 
 | 
                               } elsif ($existing_config eq "m") { 
 | 
                                       print "# $configs is m\n"; 
 | 
                                       print "# $configs=y\n"; 
 | 
                               } elsif ($existing_config eq "y") { 
 | 
                                       print "# $configs is set\n"; 
 | 
                                       print "# $configs=y\n"; 
 | 
                               } else { 
 | 
                                       print "# $configs is not set\n"; 
 | 
                                       print "# $configs=y\n"; 
 | 
                               } 
 | 
                       } 
 | 
               } 
 | 
       } 
 | 
  
 | 
       return 1; 
 | 
} 
 | 
  
 | 
  
 | 
sub scan_makefile 
 | 
{ 
 | 
       my $pn_arg_ref    = shift; 
 | 
       my $driver        = shift; 
 | 
  
 | 
       # ----- Find Kconfig symbols that enable driver 
 | 
  
 | 
       my ($dir, $base) = $driver =~ m{(.*)/(.*).c}; 
 | 
  
 | 
       my $makefile = $dir . "/Makefile"; 
 | 
       if (! -r $makefile) { 
 | 
               $makefile = $dir . "/Kbuild"; 
 | 
       } 
 | 
       if (! -r $makefile) { 
 | 
               my $config; 
 | 
  
 | 
               $config = 'no_makefile'; 
 | 
               push @{ $driver_config{$driver} }, $config; 
 | 
               return; 
 | 
       } 
 | 
  
 | 
       if (!open(MAKEFILE_FILE, "<", "$makefile")) { 
 | 
               return; 
 | 
       } 
 | 
  
 | 
       my $line; 
 | 
       my @config; 
 | 
       my @if_config; 
 | 
       my @make_var; 
 | 
  
 | 
       NEXT_LINE: 
 | 
       while ($next_line = <MAKEFILE_FILE>) { 
 | 
               my $config; 
 | 
               my $if_config; 
 | 
               my $ifdef; 
 | 
               my $ifeq; 
 | 
               my $ifndef; 
 | 
               my $ifneq; 
 | 
               my $ifdef_config; 
 | 
               my $ifeq_config; 
 | 
               my $ifndef_config; 
 | 
               my $ifneq_config; 
 | 
  
 | 
               chomp($next_line); 
 | 
               $line = $line . $next_line; 
 | 
               if ($next_line =~ /\\$/) { 
 | 
                       $line =~ s/\\$/ /; 
 | 
                       next NEXT_LINE; 
 | 
               } 
 | 
               if ($line =~ /^\s*#/) { 
 | 
                       $line = ""; 
 | 
                       next NEXT_LINE; 
 | 
               } 
 | 
  
 | 
               # -----  condition ... else ... endif 
 | 
  
 | 
               if ($line =~ /^([ ]\s*|)else\b/) { 
 | 
                       $if_config = "!" . pop @if_config; 
 | 
                       $if_config =~ s/^!!//; 
 | 
                       push @if_config, $if_config; 
 | 
                       $line =~ s/^([ ]\s*|)else\b//; 
 | 
               } 
 | 
  
 | 
               ($null, $ifeq_config,  $ifeq_config_val )  = $line =~ /^([ ]\s*|)ifeq\b.*\b(CONFIG_[A-Za-z0-9_]*)(.*)/; 
 | 
               ($null, $ifneq_config, $ifneq_config_val)  = $line =~ /^([ ]\s*|)ifneq\b.*\b(CONFIG_[A-Za-z0-9_]*)(.*)/; 
 | 
               ($null, $ifdef_config)                     = $line =~ /^([ ]\s*|)ifdef\b.*\b(CONFIG_[A-Za-z0-9_]*)/; 
 | 
               ($null, $ifndef_config)                    = $line =~ /^([ ]\s*|)ifndef\b.*\b(CONFIG_[A-Za-z0-9_]*)/; 
 | 
  
 | 
               ($null, $ifeq)   = $line =~ /^([ ]\s*|)ifeq\b\s*(.*)/; 
 | 
               ($null, $ifneq)  = $line =~ /^([ ]\s*|)ifneq\b\s*(.*)/; 
 | 
               ($null, $ifdef)  = $line =~ /^([ ]\s*|)ifdef\b\s*(.*)/; 
 | 
               ($null, $ifndef) = $line =~ /^([ ]\s*|)ifndef\b\s*(.*)/; 
 | 
  
 | 
               # Order of tests is important.  Prefer "CONFIG_*" regex match over 
 | 
               # less specific regex match. 
 | 
               if ($ifdef_config) { 
 | 
                       $if_config = $ifdef_config; 
 | 
               } elsif ($ifeq_config) { 
 | 
                       if ($ifeq_config_val =~ /y/) { 
 | 
                               $if_config = $ifeq_config; 
 | 
                       } else { 
 | 
                               $if_config = "!" . $ifeq_config; 
 | 
                       } 
 | 
               } elsif ($ifndef_config) { 
 | 
                       $if_config = "!" . $ifndef_config; 
 | 
               } elsif ($ifneq_config) { 
 | 
                       if ($ifneq_config_val =~ /y/) { 
 | 
                               $if_config = "!" . $ifneq_config; 
 | 
                       } else { 
 | 
                               $if_config = $ifneq_config; 
 | 
                       } 
 | 
               } elsif ($ifdef) { 
 | 
                       $if_config = $ifdef; 
 | 
               } elsif ($ifeq) { 
 | 
                       $if_config = $ifeq; 
 | 
               } elsif ($ifndef) { 
 | 
                       $if_config = "!" . $ifndef; 
 | 
               } elsif ($ifneq) { 
 | 
                       $if_config = "!" . $ifneq; 
 | 
               } else { 
 | 
                       $if_config = ""; 
 | 
               } 
 | 
               $if_config =~ s/^!!//; 
 | 
  
 | 
               if ($if_config) { 
 | 
                       push @if_config, $if_config; 
 | 
                       $line = ""; 
 | 
                       next NEXT_LINE; 
 | 
               } 
 | 
  
 | 
               if ($line =~ /^([ ]\s*|)endif\b/) { 
 | 
                       pop @if_config; 
 | 
                       $line = ""; 
 | 
                       next NEXT_LINE; 
 | 
               } 
 | 
  
 | 
               # ----- simple CONFIG_* = *.[co]  or  xxx [+:?]*= *.[co] 
 | 
               # Most makefiles select on *.o, but 
 | 
               # arch/powerpc/boot/Makefile selects on *.c 
 | 
  
 | 
               ($config) = $line =~ /(CONFIG_[A-Za-z0-9_]+).*\b$base.[co]\b/; 
 | 
  
 | 
               # ----- match a make variable instead of *.[co] 
 | 
               # Recursively expanded variables are not handled. 
 | 
  
 | 
               if (!$config) { 
 | 
                       my $make_var; 
 | 
                       ($make_var) = $line =~ /\s*(\S+?)\s*[+:\?]*=.*\b$base.[co]\b/; 
 | 
                       if ($make_var) { 
 | 
                               if ($make_var =~ /[a-zA-Z0-9]+-[ym]/) { 
 | 
                                       $config = $make_var; 
 | 
                               } elsif ($make_var =~ /[a-zA-Z0-9]+-objs/) { 
 | 
                                       $config = $make_var; 
 | 
                               } else { 
 | 
                                       push @make_var, $make_var; 
 | 
                               } 
 | 
                       } 
 | 
               } 
 | 
  
 | 
               if (!$config) { 
 | 
                       for $make_var (@make_var) { 
 | 
                               ($config) = $line =~ /(CONFIG_[A-Za-z0-9_]+).*\b$make_var\b/; 
 | 
                               last if ($config); 
 | 
                       } 
 | 
               } 
 | 
  
 | 
               if (!$config) { 
 | 
                       for $make_var (@make_var) { 
 | 
                               ($config) = $line =~ /\s*(\S+?)\s*[+:\?]*=.*\b$make_var\b/; 
 | 
                               last if ($config); 
 | 
                       } 
 | 
               } 
 | 
  
 | 
               # ----- next if no config found 
 | 
  
 | 
               if (!$config) { 
 | 
                       $line = ""; 
 | 
                       next NEXT_LINE; 
 | 
               } 
 | 
  
 | 
               for $if_config (@if_config) { 
 | 
                       $config = $if_config . " && " . $config; 
 | 
               } 
 | 
  
 | 
               push @{ $driver_config{$driver} }, $config; 
 | 
  
 | 
               $line = ""; 
 | 
       } 
 | 
  
 | 
       close(MAKEFILE_FILE); 
 | 
  
 | 
} 
 | 
  
 | 
  
 | 
sub find_kconfig 
 | 
{ 
 | 
       my $pn_arg_ref    = shift; 
 | 
       my $driver        = shift; 
 | 
  
 | 
       my $lines_printed = 0; 
 | 
       my @configs; 
 | 
  
 | 
       if (!@{ $driver_config{$driver} }) { 
 | 
               &scan_makefile($pn_arg_ref, $driver); 
 | 
               if (!@{ $driver_config{$driver} }) { 
 | 
                       push @{ $driver_config{$driver} }, "no_config"; 
 | 
               } 
 | 
       } 
 | 
  
 | 
       @configs = @{ $driver_config{$driver} }; 
 | 
  
 | 
       $$pn_arg_ref{config_cnt} = $#configs + 1; 
 | 
       for my $config (@configs) { 
 | 
               $$pn_arg_ref{config} = $config; 
 | 
               $lines_printed += &print_node($pn_arg_ref); 
 | 
       } 
 | 
  
 | 
       return $lines_printed; 
 | 
} 
 | 
  
 | 
  
 | 
sub handle_compatible() 
 | 
{ 
 | 
       my $full_node     = shift; 
 | 
       my $node          = shift; 
 | 
       my $compatible    = shift; 
 | 
       my $node_enabled  = shift; 
 | 
  
 | 
       my $compat; 
 | 
       my $lines_printed = 0; 
 | 
       my %pn_arg        = (); 
 | 
  
 | 
       return if (!$node or !$compatible); 
 | 
  
 | 
       # Do not process compatible property of root node, 
 | 
       # it is used to match board, not to bind a driver. 
 | 
       return if ($node eq "/"); 
 | 
  
 | 
       $pn_arg{full_node}    = $full_node; 
 | 
       $pn_arg{node}         = $node; 
 | 
       $pn_arg{node_enabled} = $node_enabled; 
 | 
  
 | 
       my @compatibles = split('", "', $compatible); 
 | 
  
 | 
       $compatibles[0] =~ s/^"//; 
 | 
       $compatibles[$#compatibles] =~ s/"$//; 
 | 
  
 | 
       $pn_arg{compatible_cnt} = $#compatibles + 1; 
 | 
  
 | 
       COMPAT: 
 | 
       for $compat (@compatibles) { 
 | 
  
 | 
               $pn_arg{compat}     = $compat; 
 | 
               $pn_arg{driver_cnt} = 0; 
 | 
               $pn_arg{white_list} = 0; 
 | 
  
 | 
               if (exists($compat_white_list{$compat})) { 
 | 
                       $pn_arg{white_list} = 1; 
 | 
                       $pn_arg{driver}     = "no_driver"; 
 | 
                       $pn_arg{config_cnt} = 1; 
 | 
                       $pn_arg{config}     = "no_config"; 
 | 
                       $lines_printed += &print_node(\%pn_arg); 
 | 
                       next COMPAT; 
 | 
               } 
 | 
  
 | 
               # ----- if compat previously seen, use cached info 
 | 
  
 | 
               if (exists($compat_driver{$compat})) { 
 | 
                       for my $driver (@{ $compat_driver{$compat} }) { 
 | 
                               $pn_arg{driver}     = $driver; 
 | 
                               $pn_arg{driver_cnt} = $driver_count{$compat}; 
 | 
                               $pn_arg{config_cnt} = $#{ $driver_config{$driver}} + 1; 
 | 
  
 | 
                               for my $config (@{ $driver_config{$driver} }) { 
 | 
                                       $pn_arg{config} = $config; 
 | 
                                       $lines_printed += &print_node(\%pn_arg); 
 | 
                               } 
 | 
  
 | 
                               if (!@{ $driver_config{$driver} }) { 
 | 
                                       # no config cached yet 
 | 
                                       # $driver in %driver_hard_code_list 
 | 
                                       # but not %driver_config_hard_code_list 
 | 
                                       $lines_printed += &find_kconfig(\%pn_arg, $driver); 
 | 
                               } 
 | 
                       } 
 | 
                       next COMPAT; 
 | 
               } 
 | 
  
 | 
  
 | 
               # ----- Find drivers (source files that contain compatible) 
 | 
  
 | 
               # this will miss arch/sparc/include/asm/parport.h 
 | 
               # It is better to move the compatible out of the .h 
 | 
               # than to add *.h. to the files list, because *.h generates 
 | 
               # a lot of false negatives. 
 | 
               my $files = '"*.c"'; 
 | 
               my $drivers = `git grep -l '"$compat"' -- $files`; 
 | 
               chomp($drivers); 
 | 
               if ($drivers eq "") { 
 | 
                       $pn_arg{driver} = "no_driver"; 
 | 
                       $pn_arg{config_cnt} = 1; 
 | 
                       $pn_arg{config} = "no_config"; 
 | 
                       push @{ $compat_driver{$compat} }, "no_driver"; 
 | 
                       $lines_printed += &print_node(\%pn_arg); 
 | 
                       next COMPAT; 
 | 
               } 
 | 
  
 | 
               my @drivers = split("\n", $drivers); 
 | 
               $driver_count{$compat} = $#drivers + 1; 
 | 
               $pn_arg{driver_cnt}    = $#drivers + 1; 
 | 
  
 | 
               DRIVER: 
 | 
               for my $driver (@drivers) { 
 | 
                       push @{ $compat_driver{$compat} }, $driver; 
 | 
                       $pn_arg{driver} = $driver; 
 | 
  
 | 
                       # ----- if driver previously seen, use cached info 
 | 
  
 | 
                       $pn_arg{config_cnt} = $#{ $driver_config{$driver} } + 1; 
 | 
                       for my $config (@{ $driver_config{$driver} }) { 
 | 
                               $pn_arg{config} = $config; 
 | 
                               $lines_printed += &print_node(\%pn_arg); 
 | 
                       } 
 | 
                       if (@{ $driver_config{$driver} }) { 
 | 
                               next DRIVER; 
 | 
                       } 
 | 
  
 | 
                       if ($black_list_driver) { 
 | 
                               for $black (@black_list_driver) { 
 | 
                                       next DRIVER if ($driver =~ /^$black$/); 
 | 
                               } 
 | 
                       } 
 | 
  
 | 
  
 | 
                       # ----- Find Kconfig symbols that enable driver 
 | 
  
 | 
                       $lines_printed += &find_kconfig(\%pn_arg, $driver); 
 | 
  
 | 
               } 
 | 
       } 
 | 
  
 | 
       # White space (line) between nodes for readability. 
 | 
       # Each node may report several compatibles. 
 | 
       # For each compatible, multiple drivers may be reported. 
 | 
       # For each driver, multiple CONFIG_ options may be reported. 
 | 
       if ($lines_printed) { 
 | 
               print "\n"; 
 | 
       } 
 | 
} 
 | 
  
 | 
sub read_dts() 
 | 
{ 
 | 
       my $file         = shift; 
 | 
  
 | 
       my $compatible   = ""; 
 | 
       my $line; 
 | 
       my $node         = ""; 
 | 
       my $node_enabled = ""; 
 | 
  
 | 
       if (! -r $file) { 
 | 
               print STDERR "file '$file' is not readable or does not exist\n"; 
 | 
               exit 3; 
 | 
       } 
 | 
  
 | 
       if (!open(DT_FILE, "-|", "$dtx_diff $file")) { 
 | 
               print STDERR "\n"; 
 | 
               print STDERR "shell command failed:\n"; 
 | 
               print STDERR "   $dtx_diff $file\n"; 
 | 
               print STDERR "\n"; 
 | 
               exit 3; 
 | 
       } 
 | 
  
 | 
       FILE: 
 | 
       while ($line = <DT_FILE>) { 
 | 
               chomp($line); 
 | 
  
 | 
               if ($line =~ /{/) { 
 | 
  
 | 
                       &handle_compatible($full_node, $node, $compatible, 
 | 
                                          $node_enabled); 
 | 
  
 | 
                       while ($end_node_count-- > 0) { 
 | 
                               pop @full_node; 
 | 
                       }; 
 | 
                       $end_node_count = 0; 
 | 
                       $full_node = @full_node[-1]; 
 | 
  
 | 
                       $node = $line; 
 | 
                       $node =~ s/^\s*(.*)\s+\{.*/$1/; 
 | 
                       $node =~ s/.*: //; 
 | 
                       if ($node eq '/' ) { 
 | 
                               $full_node = '/'; 
 | 
                       } elsif ($full_node ne '/') { 
 | 
                               $full_node = $full_node . '/' . $node; 
 | 
                       } else { 
 | 
                               $full_node = '/' . $node; 
 | 
                       } 
 | 
                       push @full_node, $full_node; 
 | 
  
 | 
                       $compatible = ""; 
 | 
                       $node_enabled = ""; 
 | 
                       next FILE; 
 | 
               } 
 | 
  
 | 
               if ($line =~ /}/) { 
 | 
                       $end_node_count++; 
 | 
               } 
 | 
  
 | 
               if ($line =~ /(\s+|^)status =/) { 
 | 
                       $node_enabled = $line; 
 | 
                       $node_enabled =~ s/^\t*//; 
 | 
                       $node_enabled =~ s/^status = "//; 
 | 
                       $node_enabled =~ s/";$//; 
 | 
                       next FILE; 
 | 
               } 
 | 
  
 | 
               if ($line =~ /(\s+|^)compatible =/) { 
 | 
                       # Extract all compatible entries for this device 
 | 
                       # White space matching here and in handle_compatible() is 
 | 
                       # precise, because input format is the output of dtc, 
 | 
                       # which is invoked by dtx_diff. 
 | 
                       $compatible = $line; 
 | 
                       $compatible =~ s/^\t*//; 
 | 
                       $compatible =~ s/^compatible = //; 
 | 
                       $compatible =~ s/;$//; 
 | 
               } 
 | 
       } 
 | 
  
 | 
       &handle_compatible($full_node, $node, $compatible, $node_enabled); 
 | 
  
 | 
       close(DT_FILE); 
 | 
} 
 | 
  
 | 
  
 | 
sub read_config_file() 
 | 
{ 
 | 
       if (! -r $config_file) { 
 | 
               print STDERR "file '$config_file' is not readable or does not exist\n"; 
 | 
               exit 2; 
 | 
       } 
 | 
  
 | 
       if (!open(CONFIG_FILE, "<", "$config_file")) { 
 | 
               print STDERR "open $config_file failed\n"; 
 | 
               exit 2; 
 | 
       } 
 | 
  
 | 
       my @line; 
 | 
  
 | 
       LINE: 
 | 
       while ($line = <CONFIG_FILE>) { 
 | 
               chomp($line); 
 | 
               next LINE if ($line =~ /^\s*#/); 
 | 
               next LINE if ($line =~ /^\s*$/); 
 | 
               @line = split /=/, $line; 
 | 
               $existing_config{@line[0]} = @line[1]; 
 | 
       } 
 | 
  
 | 
       close(CONFIG_FILE); 
 | 
} 
 | 
  
 | 
  
 | 
sub cmd_line_err() 
 | 
{ 
 | 
       my $msg = shift; 
 | 
  
 | 
       print STDERR "\n"; 
 | 
       print STDERR "   ERROR processing command line options\n"; 
 | 
       print STDERR "         $msg\n" if ($msg ne ""); 
 | 
       print STDERR "\n"; 
 | 
       print STDERR "   For help, type '$script_name --help'\n"; 
 | 
       print STDERR "\n"; 
 | 
} 
 | 
  
 | 
  
 | 
# ----------------------------------------------------------------------------- 
 | 
# program entry point 
 | 
  
 | 
Getopt::Long::Configure("no_ignore_case", "bundling"); 
 | 
  
 | 
if (!GetOptions( 
 | 
       "c=s"               => \$config_file, 
 | 
       "config=s"          => \$config_file, 
 | 
       "config-format"     => \$config_format, 
 | 
       "exclude-flag=s"    => \@exclude_flag, 
 | 
       "h"                 => \$help, 
 | 
       "help"              => \$help, 
 | 
       "black-list-driver" => \$black_list_driver, 
 | 
       "white-list-config" => \$white_list_config, 
 | 
       "white-list-driver" => \$white_list_driver, 
 | 
       "include-flag=s"    => \@include_flag, 
 | 
       "include-suspect"   => \$include_suspect, 
 | 
       "short-name"        => \$short_name, 
 | 
       "show-lists"        => \$show_lists, 
 | 
       "version"           => \$version, 
 | 
       )) { 
 | 
  
 | 
       &cmd_line_err(); 
 | 
  
 | 
       exit 1; 
 | 
} 
 | 
  
 | 
  
 | 
my $exit_after_messages = 0; 
 | 
  
 | 
if ($version) { 
 | 
       print STDERR "\n$script_name  $VUFX\n\n"; 
 | 
       $exit_after_messages = 1; 
 | 
} 
 | 
  
 | 
  
 | 
if ($help) { 
 | 
       &usage; 
 | 
       $exit_after_messages = 1; 
 | 
} 
 | 
  
 | 
  
 | 
if ($show_lists) { 
 | 
  
 | 
       print "\n"; 
 | 
       print "These compatibles are hard coded to have no driver.\n"; 
 | 
       print "\n"; 
 | 
       for my $compat (sort keys %compat_white_list) { 
 | 
               print "   $compat\n"; 
 | 
       } 
 | 
  
 | 
  
 | 
       print "\n\n"; 
 | 
       print "The driver for these compatibles is hard coded (white list).\n"; 
 | 
       print "\n"; 
 | 
       my $max_compat_len = 0; 
 | 
       for my $compat (sort keys %driver_hard_code_list) { 
 | 
               if (length $compat > $max_compat_len) { 
 | 
                       $max_compat_len = length $compat; 
 | 
               } 
 | 
       } 
 | 
       for my $compat (sort keys %driver_hard_code_list) { 
 | 
               if (($driver ne "hardcoded_no_driver") && ($driver ne "no_driver")) { 
 | 
                       my $first = 1; 
 | 
                       for my $driver (@{ $driver_hard_code_list{$compat} }) { 
 | 
                               if ($first) { 
 | 
                                       print "   $compat"; 
 | 
                                       print " " x ($max_compat_len - length $compat); 
 | 
                                       $first = 0; 
 | 
                               } else { 
 | 
                                       print "   ", " " x $max_compat_len; 
 | 
                               } 
 | 
                               print "  $driver\n"; 
 | 
                       } 
 | 
               } 
 | 
       } 
 | 
  
 | 
  
 | 
       print "\n\n"; 
 | 
       print "The configuration option for these drivers is hard coded (white list).\n"; 
 | 
       print "\n"; 
 | 
       my $max_driver_len = 0; 
 | 
       for my $driver (sort keys %driver_config_hard_code_list) { 
 | 
               if (length $driver > $max_driver_len) { 
 | 
                       $max_driver_len = length $driver; 
 | 
               } 
 | 
       } 
 | 
       for my $driver (sort keys %driver_config_hard_code_list) { 
 | 
               if (($driver ne "hardcoded_no_driver") && ($driver ne "no_driver")) { 
 | 
                       my $first = 1; 
 | 
                       for my $config (@{ $driver_config_hard_code_list{$driver} }) { 
 | 
                               if ($first) { 
 | 
                                       print "   $driver"; 
 | 
                                       print " " x ($max_driver_len - length $driver); 
 | 
                                       $first = 0; 
 | 
                               } else { 
 | 
                                       print "   ", " " x $max_driver_len; 
 | 
                               } 
 | 
                               print "  $config\n"; 
 | 
                       } 
 | 
               } 
 | 
       } 
 | 
  
 | 
  
 | 
       print "\n\n"; 
 | 
       print "These drivers are black listed.\n"; 
 | 
       print "\n"; 
 | 
       for my $driver (@black_list_driver) { 
 | 
               print "   $driver\n"; 
 | 
       } 
 | 
  
 | 
       print "\n"; 
 | 
  
 | 
       $exit_after_messages = 1; 
 | 
} 
 | 
  
 | 
  
 | 
if ($exit_after_messages) { 
 | 
       exit 0; 
 | 
} 
 | 
  
 | 
  
 | 
$exclude_flag_pattern = "["; 
 | 
for my $exclude_flag (@exclude_flag) { 
 | 
       $exclude_flag_pattern = $exclude_flag_pattern . $exclude_flag; 
 | 
} 
 | 
$exclude_flag_pattern = $exclude_flag_pattern . "]"; 
 | 
# clean up if empty 
 | 
$exclude_flag_pattern =~ s/^\[\]$//; 
 | 
  
 | 
  
 | 
$include_flag_pattern = "["; 
 | 
for my $include_flag (@include_flag) { 
 | 
       $include_flag_pattern = $include_flag_pattern . $include_flag; 
 | 
} 
 | 
$include_flag_pattern = $include_flag_pattern . "]"; 
 | 
# clean up if empty 
 | 
$include_flag_pattern =~ s/^\[\]$//; 
 | 
  
 | 
  
 | 
if ($exclude_flag_pattern) { 
 | 
       my $found = 0; 
 | 
       for $pr_flag_value (@pr_flag_value) { 
 | 
               if ($exclude_flag_pattern =~ m/$pr_flag_value/) { 
 | 
                       $found = 1; 
 | 
               } 
 | 
       } 
 | 
       if (!$found) { 
 | 
               &cmd_line_err("invalid value for FLAG in --exclude-flag\n"); 
 | 
               exit 1 
 | 
       } 
 | 
} 
 | 
  
 | 
if ($include_flag_pattern) { 
 | 
       my $found = 0; 
 | 
       for $pr_flag_value (@pr_flag_value) { 
 | 
               if ($include_flag_pattern =~ m/$pr_flag_value/) { 
 | 
                       $found = 1; 
 | 
               } 
 | 
       } 
 | 
       if (!$found) { 
 | 
               &cmd_line_err("invalid value for FLAG in --include-flag\n"); 
 | 
               exit 1 
 | 
       } 
 | 
} 
 | 
  
 | 
if ($include_suspect) { 
 | 
       $include_flag_pattern =~ s/\[//; 
 | 
       $include_flag_pattern =~ s/\]//; 
 | 
       $include_flag_pattern = "[" . $include_flag_pattern . "A-Z]"; 
 | 
} 
 | 
  
 | 
if ($exclude_flag_pattern =~ m/$include_flag_pattern/) { 
 | 
       &cmd_line_err("the same flag appears in both --exclude-flag and --include-flag or --include-suspect\n"); 
 | 
       exit 1 
 | 
} 
 | 
  
 | 
  
 | 
# ($#ARGV < 0) is valid for --help, --version 
 | 
if ($#ARGV < 0) { 
 | 
       &cmd_line_err("device-tree... is required"); 
 | 
       exit 1 
 | 
} 
 | 
  
 | 
  
 | 
if ($config_file) { 
 | 
       &read_config_file(); 
 | 
} 
 | 
  
 | 
  
 | 
# avoid pushing duplicates for this value 
 | 
$driver = "hardcoded_no_driver"; 
 | 
for $config ( @{ $driver_config_hard_code_list{$driver} } ) { 
 | 
       push @{ $driver_config{$driver} }, $config; 
 | 
} 
 | 
  
 | 
if ($white_list_driver) { 
 | 
       for my $compat (keys %driver_hard_code_list) { 
 | 
               for my $driver (@{ $driver_hard_code_list{$compat} }) { 
 | 
                       push @{ $compat_driver{$compat} }, $driver; 
 | 
                       if ($driver ne "hardcoded_no_driver") { 
 | 
                               $driver_count{$compat} = scalar @{ $compat_driver{$compat} }; 
 | 
                       } 
 | 
               } 
 | 
       } 
 | 
} 
 | 
  
 | 
if ($white_list_config) { 
 | 
       for my $driver (keys %driver_config_hard_code_list) { 
 | 
               if ($driver ne "hardcoded_no_driver") { 
 | 
                       for $config ( @{ $driver_config_hard_code_list{$driver} } ) { 
 | 
                               push @{ $driver_config{$driver} }, $config; 
 | 
                       } 
 | 
               } 
 | 
       } 
 | 
} 
 | 
  
 | 
if (-x "scripts/dtc/dtx_diff") { 
 | 
       $dtx_diff = "scripts/dtc/dtx_diff"; 
 | 
} else { 
 | 
  
 | 
       print STDERR "\n"; 
 | 
       print STDERR "$script_name must be run from the root directory of a Linux kernel tree\n"; 
 | 
       print STDERR "\n"; 
 | 
       exit 3; 
 | 
} 
 | 
  
 | 
for $file (@ARGV) { 
 | 
       &read_dts($file); 
 | 
} 
 |