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(str, len, "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(str, len, "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, 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, size); 76 str[size - 1] = '\0'; 77 ret = request_module(str); 78 kfree(str); 79 80 return ret; 81 } 82 EXPORT_SYMBOL_GPL(of_request_module); 83