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