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@xxxxxxxxxxxxxx> --- 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