[PATCH] 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>
---
 commands/Kconfig         |  15 +++++
 commands/Makefile        |   1 +
 commands/of_compatible.c | 139 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+)
 create mode 100644 commands/of_compatible.c

diff --git a/commands/Kconfig b/commands/Kconfig
index b9abd8565523..59e8d6fb382d 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 comptible (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..e4684f23b71d
--- /dev/null
+++ b/commands/of_compatible.c
@@ -0,0 +1,139 @@
+// 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 *dtbfile = NULL;
+	const char *compat, *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;
+
+	compat = argv[optind];
+
+	if (dtbfile) {
+		size_t size;
+		void *fdt;
+
+		fdt = read_file(dtbfile, &size);
+		if (!fdt) {
+			printf("unable to read %s: %s\n", dtbfile, strerror(errno));
+			return -errno;
+		}
+
+		root = of_unflatten_dtb(fdt, size);
+
+		free(fdt);
+
+		if (IS_ERR(root)) {
+			ret = PTR_ERR(root);
+			goto out;
+		}
+
+		of_free = root;
+	} else {
+		root = of_get_root_node();
+
+		if (fix) {
+			/* create a copy of internal devicetree */
+			void *fdt;
+			fdt = of_flatten_dtb(root);
+			root = of_unflatten_dtb(fdt, fdt_totalsize(fdt));
+
+			free(fdt);
+
+			if (IS_ERR(root)) {
+				ret = PTR_ERR(root);
+				goto out;
+			}
+
+			of_free = 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;
+	}
+
+	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() ?: "";
+		if (strcmp(compat_override, compat) == 0) {
+			ret = 0;
+			goto out;
+		}
+	}
+
+	ret = !of_device_is_compatible(node, compat);
+
+out:
+	if (of_free)
+		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] [COMPAT]")
+	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