1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Linux kernel module helpers.
4 */
5
6#include <linux/of.h>
7#include <linux/module.h>
8#include <linux/slab.h>
9#include <linux/string.h>
10
11ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len)
12{
13 const char *compat;
14 char *c;
15 struct property *p;
16 ssize_t csize;
17 ssize_t tsize;
18
19 /*
20 * Prevent a kernel oops in vsnprintf() -- it only allows passing a
21 * NULL ptr when the length is also 0. Also filter out the negative
22 * lengths...
23 */
24 if ((len > 0 && !str) || len < 0)
25 return -EINVAL;
26
27 /* Name & Type */
28 /* %p eats all alphanum characters, so %c must be used here */
29 csize = snprintf(buf: str, size: len, fmt: "of:N%pOFn%c%s", np, 'T',
30 of_node_get_device_type(np));
31 tsize = csize;
32 len -= csize;
33 if (str)
34 str += csize;
35
36 of_property_for_each_string(np, "compatible", p, compat) {
37 csize = strlen(compat) + 1;
38 tsize += csize;
39 if (csize > len)
40 continue;
41
42 csize = snprintf(buf: str, size: len, fmt: "C%s", compat);
43 for (c = str; c; ) {
44 c = strchr(c, ' ');
45 if (c)
46 *c++ = '_';
47 }
48 len -= csize;
49 str += csize;
50 }
51
52 return tsize;
53}
54
55int of_request_module(const struct device_node *np)
56{
57 char *str;
58 ssize_t size;
59 int ret;
60
61 if (!np)
62 return -ENODEV;
63
64 size = of_modalias(np, NULL, len: 0);
65 if (size < 0)
66 return size;
67
68 /* Reserve an additional byte for the trailing '\0' */
69 size++;
70
71 str = kmalloc(size, GFP_KERNEL);
72 if (!str)
73 return -ENOMEM;
74
75 of_modalias(np, str, len: size);
76 str[size - 1] = '\0';
77 ret = request_module(str);
78 kfree(objp: str);
79
80 return ret;
81}
82EXPORT_SYMBOL_GPL(of_request_module);
83

source code of linux/drivers/of/module.c