| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283 |
- // SPDX-License-Identifier: GPL-2.0
- /*
- * Linux kernel module helpers.
- */
- #include <linux/of.h>
- #include <linux/module.h>
- #include <linux/slab.h>
- #include <linux/string.h>
- ssize_t of_modalias(const struct device_node *np, char *str, ssize_t len)
- {
- const char *compat;
- char *c;
- struct property *p;
- ssize_t csize;
- ssize_t tsize;
- /*
- * Prevent a kernel oops in vsnprintf() -- it only allows passing a
- * NULL ptr when the length is also 0. Also filter out the negative
- * lengths...
- */
- if ((len > 0 && !str) || len < 0)
- return -EINVAL;
- /* Name & Type */
- /* %p eats all alphanum characters, so %c must be used here */
- csize = snprintf(str, len, "of:N%pOFn%c%s", np, 'T',
- of_node_get_device_type(np));
- tsize = csize;
- if (csize >= len)
- csize = len > 0 ? len - 1 : 0;
- len -= csize;
- str += csize;
- of_property_for_each_string(np, "compatible", p, compat) {
- csize = strlen(compat) + 1;
- tsize += csize;
- if (csize >= len)
- continue;
- csize = snprintf(str, len, "C%s", compat);
- for (c = str; c; ) {
- c = strchr(c, ' ');
- if (c)
- *c++ = '_';
- }
- len -= csize;
- str += csize;
- }
- return tsize;
- }
- int of_request_module(const struct device_node *np)
- {
- char *str;
- ssize_t size;
- int ret;
- if (!np)
- return -ENODEV;
- size = of_modalias(np, NULL, 0);
- if (size < 0)
- return size;
- /* Reserve an additional byte for the trailing '\0' */
- size++;
- str = kmalloc(size, GFP_KERNEL);
- if (!str)
- return -ENOMEM;
- of_modalias(np, str, size);
- str[size - 1] = '\0';
- ret = request_module(str);
- kfree(str);
- return ret;
- }
- EXPORT_SYMBOL_GPL(of_request_module);
|