diff options
Diffstat (limited to 'drivers/of/module.c')
| -rw-r--r-- | drivers/of/module.c | 74 | 
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/of/module.c b/drivers/of/module.c new file mode 100644 index 000000000000..0e8aa974f0f2 --- /dev/null +++ b/drivers/of/module.c @@ -0,0 +1,74 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Linux kernel module helpers. + */ + +#include <linux/of.h> +#include <linux/module.h> +#include <linux/slab.h> +#include <linux/string.h> + +ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len) +{ +	const char *compat; +	char *c; +	struct property *p; +	ssize_t csize; +	ssize_t tsize; + +	/* Name & Type */ +	/* %p eats all alphanum characters, so %c must be used here */ +	csize = snprintf(str, len, "of:N%pOFn%c%s", np, 'T', +			 of_node_get_device_type(np)); +	tsize = csize; +	len -= csize; +	if (str) +		str += csize; + +	of_property_for_each_string(np, "compatible", p, compat) { +		csize = strlen(compat) + 1; +		tsize += csize; +		if (csize > len) +			continue; + +		csize = snprintf(str, len, "C%s", compat); +		for (c = str; c; ) { +			c = strchr(c, ' '); +			if (c) +				*c++ = '_'; +		} +		len -= csize; +		str += csize; +	} + +	return tsize; +} + +int of_request_module(const struct device_node *np) +{ +	char *str; +	ssize_t size; +	int ret; + +	if (!np) +		return -ENODEV; + +	size = of_modalias(np, NULL, 0); +	if (size < 0) +		return size; + +	/* Reserve an additional byte for the trailing '\0' */ +	size++; + +	str = kmalloc(size, GFP_KERNEL); +	if (!str) +		return -ENOMEM; + +	of_modalias(np, str, size); +	str[size - 1] = '\0'; +	ret = request_module(str); +	kfree(str); + +	return ret; +} +EXPORT_SYMBOL_GPL(of_request_module);  |