[PATCH v2 6/6] commands: implement of_compatible command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Currently, the usual way within scripts to differentiate between machines
is to compare global.model or global.hostname. Both are suboptimal,
because they may change between releases or overridden by the user.

In C code, the machine compatible is used for this purpose. Add a new
of_compatible command that makes of_machine_is_compatible/
of_device_is_compatible available to scripts. Example use:

/env/init/fixups:

  #!/bin/sh

  if of_compatible -k radxa,rock3a ; then
    of_property -df mmc0 sd-uhs-sdr104
  fi

Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx>
---
v1 -> v2:
  - fix typo in Kconfig help text (Sascha)
  - use of_dup/of_read_file (Sascha)
  - fix return code if compatibles don't match
  - support multiple compatibles
  - Kconfig whitespace adjustments
---
 commands/Kconfig         |  15 +++++
 commands/Makefile        |   1 +
 commands/of_compatible.c | 124 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 140 insertions(+)
 create mode 100644 commands/of_compatible.c

diff --git a/commands/Kconfig b/commands/Kconfig
index 9f64d90a5812..4e0cd2943116 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -2201,6 +2201,21 @@ config CMD_LSMOD
 	help
 	  List loaded barebox modules.
 
+config CMD_OF_COMPATIBLE
+	tristate
+	select OFTREE
+	prompt "of_compatible"
+	help
+	  Check DT node's compatible
+
+	  Usage: [-fFnk] [COMPAT]
+
+	  Options:
+		-f dtb	work on dtb instead of internal devicetree
+		-F	apply fixups on devicetree before compare
+		-n node	node path or alias to compare its compatible (default is /)
+		-k	compare $global.of.kernel.add_machine_compatible as well
+
 config CMD_OF_DIFF
 	tristate
 	select OFTREE
diff --git a/commands/Makefile b/commands/Makefile
index e5cc21f1970a..0ac84076f83d 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -82,6 +82,7 @@ obj-$(CONFIG_CMD_USB)		+= usb.o
 obj-$(CONFIG_CMD_TIME)		+= time.o
 obj-$(CONFIG_CMD_UPTIME)	+= uptime.o
 obj-$(CONFIG_CMD_OFTREE)	+= oftree.o
+obj-$(CONFIG_CMD_OF_COMPATIBLE)	+= of_compatible.o
 obj-$(CONFIG_CMD_OF_DIFF)	+= of_diff.o
 obj-$(CONFIG_CMD_OF_PROPERTY)	+= of_property.o
 obj-$(CONFIG_CMD_OF_NODE)	+= of_node.o
diff --git a/commands/of_compatible.c b/commands/of_compatible.c
new file mode 100644
index 000000000000..b460fecd3a86
--- /dev/null
+++ b/commands/of_compatible.c
@@ -0,0 +1,124 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: © 2023 Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx>
+
+#include <common.h>
+#include <libfile.h>
+#include <fdt.h>
+#include <of.h>
+#include <command.h>
+#include <complete.h>
+#include <errno.h>
+#include <getopt.h>
+
+static int do_of_compatible(int argc, char *argv[])
+{
+	int opt;
+	int ret = 0;
+	bool fix = false, kernel_compat = false;
+	struct device_node *root = NULL, *node, *of_free = NULL;
+	char **compats, **compat, *dtbfile = NULL;
+	const char *nodename = "/";
+
+	while ((opt = getopt(argc, argv, "f:n:Fk")) > 0) {
+		switch (opt) {
+		case 'f':
+			dtbfile = optarg;
+			break;
+		case 'n':
+			nodename = optarg;
+			break;
+		case 'F':
+			fix = true;
+			break;
+		case 'k':
+			kernel_compat = true;
+			break;
+		default:
+			return COMMAND_ERROR_USAGE;
+		}
+	}
+
+	if (argc - optind < 1)
+		return COMMAND_ERROR_USAGE;
+
+	compats = &argv[optind];
+
+	if (dtbfile) {
+		root = of_read_file(dtbfile);
+		if (IS_ERR(root))
+			return PTR_ERR(root);
+
+		of_free = root;
+	} else {
+		root = of_get_root_node();
+
+		/* copy internal device tree to apply fixups onto it */
+		if (fix)
+			root = of_free = of_dup(root);
+	}
+
+	if (fix) {
+		ret = of_fix_tree(root);
+		if (ret)
+			goto out;
+	}
+
+	node = of_find_node_by_path_or_alias(root, nodename);
+	if (!node) {
+		printf("Cannot find nodepath %s\n", nodename);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	ret = COMMAND_ERROR;
+
+	if (kernel_compat) {
+		const char *compat_override;
+
+		if (node->parent) {
+			printf("-k only valid for root node\n");
+			ret = COMMAND_ERROR_USAGE;
+			goto out;
+		}
+
+		compat_override = barebox_get_of_machine_compatible() ?: "";
+		for (compat = compats; *compat; compat++) {
+			if (strcmp(*compat, compat_override) == 0) {
+				ret = COMMAND_SUCCESS;
+				goto out;
+			}
+		}
+	}
+
+	for (compat = compats; *compat; compat++) {
+		int score;
+
+		score = of_device_is_compatible(node, *compat);
+		if (score > 0) {
+			ret = COMMAND_SUCCESS;
+			break;
+		}
+	}
+
+out:
+	of_delete_node(of_free);
+
+	return ret;
+}
+
+BAREBOX_CMD_HELP_START(of_compatible)
+BAREBOX_CMD_HELP_TEXT("Options:")
+BAREBOX_CMD_HELP_OPT  ("-f dtb",  "work on dtb instead of internal devicetree")
+BAREBOX_CMD_HELP_OPT  ("-F",      "apply fixups on devicetree before compare")
+BAREBOX_CMD_HELP_OPT  ("-n node", "node path or alias to compare its compatible (default is /)")
+BAREBOX_CMD_HELP_OPT  ("-k",      "compare $global.of.kernel.add_machine_compatible as well")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(of_compatible)
+	.cmd		= do_of_compatible,
+	BAREBOX_CMD_DESC("Check DT node's compatible")
+	BAREBOX_CMD_OPTS("[-fFnk] [COMPATS..]")
+	BAREBOX_CMD_GROUP(CMD_GRP_MISC)
+	BAREBOX_CMD_COMPLETE(empty_complete)
+	BAREBOX_CMD_HELP(cmd_of_compatible_help)
+BAREBOX_CMD_END
-- 
2.39.2





[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux