[PATCH 1/3] driver: add support for device aliases

Ahmad Fatoum a.fatoum at pengutronix.de
Wed Sep 13 06:24:54 PDT 2023


Device names can get quite long, which makes them cumbersome to use
on the shell, e.g.  firmware:zynqmp-firmware:clock-controller.of.

In addition, the names are prone to change when the device tree nodes
are renamed.

One way we work around this is using aliases, but that is partially at
odds with upstream binding. This commit adds an alternative way of
allowing drivers and board code to set an alias that affects only
device_param_complete.

This provides an easy way of defining device names that should be stable
for use in shell scripts.

Signed-off-by: Ahmad Fatoum <a.fatoum at pengutronix.de>
---
 common/complete.c     | 14 ++++++-------
 drivers/base/driver.c | 46 +++++++++++++++++++++++++++++++++++++++++++
 include/driver.h      |  7 +++++++
 3 files changed, 59 insertions(+), 8 deletions(-)

diff --git a/common/complete.c b/common/complete.c
index e9f3f8ee033f..4137bb3084fc 100644
--- a/common/complete.c
+++ b/common/complete.c
@@ -154,8 +154,8 @@ int device_complete(struct string_list *sl, char *instr)
 }
 EXPORT_SYMBOL(device_complete);
 
-static int device_param_complete(struct device *dev, struct string_list *sl,
-				 char *instr, int eval)
+static int device_param_complete(struct device *dev, const char *devname,
+				 struct string_list *sl, char *instr, int eval)
 {
 	struct param_d *param;
 	int len;
@@ -167,7 +167,7 @@ static int device_param_complete(struct device *dev, struct string_list *sl,
 			continue;
 
 		string_list_add_asprintf(sl, "%s%s.%s%c",
-			eval ? "$" : "", dev_name(dev), param->name,
+			eval ? "$" : "", devname, param->name,
 			eval ? ' ' : '=');
 	}
 
@@ -308,14 +308,12 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval)
 		char *devname;
 
 		devname = xstrndup(instr, dot - instr);
-
-
 		dev = get_device_by_name(devname);
-		free(devname);
 
 		if (dev)
-			device_param_complete(dev, sl, dot + 1, eval);
+			device_param_complete(dev, devname, sl, dot + 1, eval);
 
+		free(devname);
 		pos = dot + 1;
 	}
 
@@ -323,7 +321,7 @@ static int env_param_complete(struct string_list *sl, char *instr, int eval)
 
 	for_each_device(dev) {
 		if (!strncmp(instr, dev_name(dev), len))
-			device_param_complete(dev, sl, "", eval);
+			device_param_complete(dev, dev_name(dev), sl, "", eval);
 	}
 
 	return 0;
diff --git a/drivers/base/driver.c b/drivers/base/driver.c
index 10d765e1a213..5811c7a11b75 100644
--- a/drivers/base/driver.c
+++ b/drivers/base/driver.c
@@ -24,6 +24,7 @@
 #include <fs.h>
 #include <of.h>
 #include <linux/list.h>
+#include <linux/overflow.h>
 #include <linux/err.h>
 #include <complete.h>
 #include <pinctrl.h>
@@ -46,6 +47,8 @@ LIST_HEAD(active_device_list);
 EXPORT_SYMBOL(active_device_list);
 static LIST_HEAD(deferred);
 
+static LIST_HEAD(device_alias_list);
+
 struct device *find_device(const char *str)
 {
 	struct device *dev;
@@ -65,12 +68,18 @@ struct device *find_device(const char *str)
 struct device *get_device_by_name(const char *name)
 {
 	struct device *dev;
+	struct device_alias *alias;
 
 	for_each_device(dev) {
 		if(!strcmp(dev_name(dev), name))
 			return dev;
 	}
 
+	list_for_each_entry(alias, &device_alias_list, list) {
+		if(!strcmp(alias->name, name))
+			return alias->dev;
+	}
+
 	return NULL;
 }
 
@@ -261,6 +270,7 @@ EXPORT_SYMBOL(register_device);
 
 int unregister_device(struct device *old_dev)
 {
+	struct device_alias *alias, *at;
 	struct cdev *cdev, *ct;
 	struct device *child, *dt;
 
@@ -271,6 +281,11 @@ int unregister_device(struct device *old_dev)
 	if (old_dev->driver)
 		old_dev->bus->remove(old_dev);
 
+	list_for_each_entry_safe(alias, at, &device_alias_list, list) {
+		if(alias->dev == old_dev)
+			list_del(&alias->list);
+	}
+
 	list_for_each_entry_safe(child, dt, &old_dev->children, sibling) {
 		dev_dbg(old_dev, "unregister child %s\n", dev_name(child));
 		unregister_device(child);
@@ -592,6 +607,37 @@ int dev_set_name(struct device *dev, const char *fmt, ...)
 }
 EXPORT_SYMBOL_GPL(dev_set_name);
 
+/**
+ * dev_add_alias - add alias for device
+ * @dev: device
+ * @fmt: format string for the device's alias
+ */
+int dev_add_alias(struct device *dev, const char *fmt, ...)
+{
+	va_list va, va_copy;
+	unsigned int len;
+	struct device_alias *alias;
+
+	va_start(va, fmt);
+	va_copy(va_copy, va);
+	len = vsnprintf(NULL, 0, fmt, va_copy);
+	va_end(va_copy);
+
+	alias = malloc(struct_size(alias, name, len + 1));
+	if (!alias)
+		return -ENOMEM;
+
+	vsnprintf(alias->name, len + 1, fmt, va);
+
+	va_end(va);
+
+	alias->dev = dev;
+	list_add_tail(&alias->list, &device_alias_list);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(dev_set_alias);
+
 static void devices_shutdown(void)
 {
 	struct device *dev;
diff --git a/include/driver.h b/include/driver.h
index 2651cddecc21..a0234fb6c31b 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -101,6 +101,12 @@ struct device {
 	char *deferred_probe_reason;
 };
 
+struct device_alias {
+	struct device *dev;
+	struct list_head list;
+	char name[];
+};
+
 /** @brief Describes a driver present in the system */
 struct driver {
 	/*! The name of this driver. Used to match to
@@ -216,6 +222,7 @@ static inline const char *dev_name(const struct device *dev)
 }
 
 int dev_set_name(struct device *dev, const char *fmt, ...);
+int dev_add_alias(struct device *dev, const char *fmt, ...);
 
 /*
  * get resource 'num' for a device
-- 
2.39.2




More information about the barebox mailing list