xref: /openbmc/linux/drivers/of/module.c (revision 0c6dfa75)
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 	/* Name & Type */
20 	/* %p eats all alphanum characters, so %c must be used here */
21 	csize = snprintf(str, len, "of:N%pOFn%c%s", np, 'T',
22 			 of_node_get_device_type(np));
23 	tsize = csize;
24 	len -= csize;
25 	if (str)
26 		str += csize;
27 
28 	of_property_for_each_string(np, "compatible", p, compat) {
29 		csize = strlen(compat) + 1;
30 		tsize += csize;
31 		if (csize > len)
32 			continue;
33 
34 		csize = snprintf(str, len, "C%s", compat);
35 		for (c = str; c; ) {
36 			c = strchr(c, ' ');
37 			if (c)
38 				*c++ = '_';
39 		}
40 		len -= csize;
41 		str += csize;
42 	}
43 
44 	return tsize;
45 }
46 
47 int of_request_module(const struct device_node *np)
48 {
49 	char *str;
50 	ssize_t size;
51 	int ret;
52 
53 	if (!np)
54 		return -ENODEV;
55 
56 	size = of_modalias(np, NULL, 0);
57 	if (size < 0)
58 		return size;
59 
60 	/* Reserve an additional byte for the trailing '\0' */
61 	size++;
62 
63 	str = kmalloc(size, GFP_KERNEL);
64 	if (!str)
65 		return -ENOMEM;
66 
67 	of_modalias(np, str, size);
68 	str[size - 1] = '\0';
69 	ret = request_module(str);
70 	kfree(str);
71 
72 	return ret;
73 }
74 EXPORT_SYMBOL_GPL(of_request_module);
75