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); |