root/drivers/of/module.c
// 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;

        /*
         * Prevent a kernel oops in vsnprintf() -- it only allows passing a
         * NULL ptr when the length is also 0. Also filter out the negative
         * lengths...
         */
        if ((len > 0 && !str) || len < 0)
                return -EINVAL;

        /* 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;
        if (csize >= len)
                csize = len > 0 ? len - 1 : 0;
        len -= csize;
        str += csize;

        of_property_for_each_string(np, "compatible", p, compat) {
                csize = snprintf(str, len, "C%s", compat);
                tsize += csize;
                if (csize >= len)
                        continue;
                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);