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 if (csize >= len) 33 csize = len > 0 ? len - 1 : 0; 34 len -= csize; 35 str += csize; 36 37 of_property_for_each_string(np, "compatible", p, compat) { 38 csize = snprintf(str, len, "C%s", compat); 39 tsize += csize; 40 if (csize >= len) 41 continue; 42 for (c = str; c; ) { 43 c = strchr(c, ' '); 44 if (c) 45 *c++ = '_'; 46 } 47 len -= csize; 48 str += csize; 49 } 50 51 return tsize; 52 } 53 54 int of_request_module(const struct device_node *np) 55 { 56 char *str; 57 ssize_t size; 58 int ret; 59 60 if (!np) 61 return -ENODEV; 62 63 size = of_modalias(np, NULL, 0); 64 if (size < 0) 65 return size; 66 67 /* Reserve an additional byte for the trailing '\0' */ 68 size++; 69 70 str = kmalloc(size, GFP_KERNEL); 71 if (!str) 72 return -ENOMEM; 73 74 of_modalias(np, str, size); 75 str[size - 1] = '\0'; 76 ret = request_module(str); 77 kfree(str); 78 79 return ret; 80 } 81 EXPORT_SYMBOL_GPL(of_request_module); 82