84 lines · c
1// SPDX-License-Identifier: GPL-2.02/*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 11ssize_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 a21 * NULL ptr when the length is also 0. Also filter out the negative22 * 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 56int 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}83EXPORT_SYMBOL_GPL(of_request_module);84