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 }