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 | |
11 | ssize_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 | |
55 | int 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 | } |
82 | EXPORT_SYMBOL_GPL(of_request_module); |
83 | |