2023-04-04 18:21:17 +01:00
// SPDX-License-Identifier: GPL-2.0
/*
* Linux kernel module helpers .
*/
# include <linux/of.h>
2023-04-04 18:21:18 +01:00
# include <linux/module.h>
2023-04-04 18:21:17 +01:00
# 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 ;
2024-03-27 19:52:49 +03:00
/*
* 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 ;
2023-04-04 18:21:17 +01:00
/* 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 ;
2024-04-14 11:51:39 +03:00
if ( csize > = len )
csize = len > 0 ? len - 1 : 0 ;
2023-04-04 18:21:17 +01:00
len - = csize ;
2024-04-14 11:51:39 +03:00
str + = csize ;
2023-04-04 18:21:17 +01:00
of_property_for_each_string ( np , " compatible " , p , compat ) {
csize = strlen ( compat ) + 1 ;
tsize + = csize ;
2024-04-14 11:51:39 +03:00
if ( csize > = len )
2023-04-04 18:21:17 +01:00
continue ;
csize = snprintf ( str , len , " C%s " , compat ) ;
for ( c = str ; c ; ) {
c = strchr ( c , ' ' ) ;
if ( c )
* c + + = ' _ ' ;
}
len - = csize ;
str + = csize ;
}
return tsize ;
}
2023-04-04 18:21:18 +01:00
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 ) ;