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