2019-06-21 08:18:32 -06:00
// SPDX-License-Identifier: (GPL-2.0-or-later OR BSD-2-Clause)
2007-12-10 14:28:39 +11:00
/*
* libfdt - Flat Device Tree manipulation
* Copyright ( C ) 2006 David Gibson , IBM Corporation .
*/
# include "libfdt_env.h"
# include <fdt.h>
# include <libfdt.h>
# include "libfdt_internal.h"
2018-02-27 17:40:38 -06:00
static int fdt_nodename_eq_ ( const void * fdt , int offset ,
2008-08-07 12:24:17 +10:00
const char * s , int len )
2007-12-10 14:28:39 +11:00
{
2018-02-27 17:40:38 -06:00
int olen ;
const char * p = fdt_get_name ( fdt , offset , & olen ) ;
2007-12-10 14:28:39 +11:00
2018-02-27 17:40:38 -06:00
if ( ! p | | olen < len )
2007-12-10 14:28:39 +11:00
/* short match */
return 0 ;
if ( memcmp ( p , s , len ) ! = 0 )
return 0 ;
if ( p [ len ] = = ' \0 ' )
return 1 ;
else if ( ! memchr ( s , ' @ ' , len ) & & ( p [ len ] = = ' @ ' ) )
return 1 ;
else
return 0 ;
}
2018-09-13 08:59:25 -05:00
const char * fdt_get_string ( const void * fdt , int stroffset , int * lenp )
{
2020-03-13 08:56:58 -05:00
int32_t totalsize ;
uint32_t absoffset ;
2018-09-13 08:59:25 -05:00
size_t len ;
int err ;
const char * s , * n ;
2020-03-13 08:56:58 -05:00
if ( can_assume ( VALID_INPUT ) ) {
s = ( const char * ) fdt + fdt_off_dt_strings ( fdt ) + stroffset ;
if ( lenp )
* lenp = strlen ( s ) ;
return s ;
}
totalsize = fdt_ro_probe_ ( fdt ) ;
2019-12-26 15:36:47 -07:00
err = totalsize ;
if ( totalsize < 0 )
2018-09-13 08:59:25 -05:00
goto fail ;
err = - FDT_ERR_BADOFFSET ;
2020-03-13 08:56:58 -05:00
absoffset = stroffset + fdt_off_dt_strings ( fdt ) ;
2020-10-12 09:58:15 -05:00
if ( absoffset > = ( unsigned ) totalsize )
2018-09-13 08:59:25 -05:00
goto fail ;
2019-12-26 15:36:47 -07:00
len = totalsize - absoffset ;
2018-09-13 08:59:25 -05:00
if ( fdt_magic ( fdt ) = = FDT_MAGIC ) {
if ( stroffset < 0 )
goto fail ;
2020-03-13 08:56:58 -05:00
if ( can_assume ( LATEST ) | | fdt_version ( fdt ) > = 17 ) {
2020-10-12 09:58:15 -05:00
if ( ( unsigned ) stroffset > = fdt_size_dt_strings ( fdt ) )
2018-09-13 08:59:25 -05:00
goto fail ;
if ( ( fdt_size_dt_strings ( fdt ) - stroffset ) < len )
len = fdt_size_dt_strings ( fdt ) - stroffset ;
}
} else if ( fdt_magic ( fdt ) = = FDT_SW_MAGIC ) {
2020-10-12 09:58:15 -05:00
unsigned int sw_stroffset = - stroffset ;
if ( ( stroffset > = 0 ) | |
( sw_stroffset > fdt_size_dt_strings ( fdt ) ) )
2018-09-13 08:59:25 -05:00
goto fail ;
2020-10-12 09:58:15 -05:00
if ( sw_stroffset < len )
len = sw_stroffset ;
2018-09-13 08:59:25 -05:00
} else {
err = - FDT_ERR_INTERNAL ;
goto fail ;
}
s = ( const char * ) fdt + absoffset ;
n = memchr ( s , ' \0 ' , len ) ;
if ( ! n ) {
/* missing terminating NULL */
err = - FDT_ERR_TRUNCATED ;
goto fail ;
}
if ( lenp )
* lenp = n - s ;
return s ;
fail :
if ( lenp )
* lenp = err ;
return NULL ;
}
2007-12-10 14:28:39 +11:00
const char * fdt_string ( const void * fdt , int stroffset )
{
2018-09-13 08:59:25 -05:00
return fdt_get_string ( fdt , stroffset , NULL ) ;
2007-12-10 14:28:39 +11:00
}
2018-02-27 17:40:38 -06:00
static int fdt_string_eq_ ( const void * fdt , int stroffset ,
2012-09-28 21:25:59 +00:00
const char * s , int len )
{
2018-09-13 08:59:25 -05:00
int slen ;
const char * p = fdt_get_string ( fdt , stroffset , & slen ) ;
2012-09-28 21:25:59 +00:00
2018-09-13 08:59:25 -05:00
return p & & ( slen = = len ) & & ( memcmp ( p , s , len ) = = 0 ) ;
2012-09-28 21:25:59 +00:00
}
2019-06-12 07:05:52 -06:00
int fdt_find_max_phandle ( const void * fdt , uint32_t * phandle )
2017-01-04 10:45:20 -06:00
{
2019-06-12 07:05:52 -06:00
uint32_t max = 0 ;
int offset = - 1 ;
2017-01-04 10:45:20 -06:00
2019-06-12 07:05:52 -06:00
while ( true ) {
uint32_t value ;
2017-01-04 10:45:20 -06:00
2019-06-12 07:05:52 -06:00
offset = fdt_next_node ( fdt , offset , NULL ) ;
if ( offset < 0 ) {
if ( offset = = - FDT_ERR_NOTFOUND )
break ;
2017-01-04 10:45:20 -06:00
2019-06-12 07:05:52 -06:00
return offset ;
}
2017-01-04 10:45:20 -06:00
2019-06-12 07:05:52 -06:00
value = fdt_get_phandle ( fdt , offset ) ;
2017-01-04 10:45:20 -06:00
2019-06-12 07:05:52 -06:00
if ( value > max )
max = value ;
2017-01-04 10:45:20 -06:00
}
2019-06-12 07:05:52 -06:00
if ( phandle )
* phandle = max ;
return 0 ;
}
int fdt_generate_phandle ( const void * fdt , uint32_t * phandle )
{
uint32_t max ;
int err ;
err = fdt_find_max_phandle ( fdt , & max ) ;
if ( err < 0 )
return err ;
if ( max = = FDT_MAX_PHANDLE )
return - FDT_ERR_NOPHANDLES ;
if ( phandle )
* phandle = max + 1 ;
2017-01-04 10:45:20 -06:00
return 0 ;
}
2018-09-13 08:59:25 -05:00
static const struct fdt_reserve_entry * fdt_mem_rsv ( const void * fdt , int n )
{
2020-10-12 09:58:15 -05:00
unsigned int offset = n * sizeof ( struct fdt_reserve_entry ) ;
unsigned int absoffset = fdt_off_mem_rsvmap ( fdt ) + offset ;
2018-09-13 08:59:25 -05:00
2020-03-13 08:56:58 -05:00
if ( ! can_assume ( VALID_INPUT ) ) {
if ( absoffset < fdt_off_mem_rsvmap ( fdt ) )
return NULL ;
if ( absoffset > fdt_totalsize ( fdt ) -
sizeof ( struct fdt_reserve_entry ) )
return NULL ;
}
2018-09-13 08:59:25 -05:00
return fdt_mem_rsv_ ( fdt , n ) ;
}
2007-12-10 14:28:39 +11:00
int fdt_get_mem_rsv ( const void * fdt , int n , uint64_t * address , uint64_t * size )
{
2018-09-13 08:59:25 -05:00
const struct fdt_reserve_entry * re ;
FDT_RO_PROBE ( fdt ) ;
re = fdt_mem_rsv ( fdt , n ) ;
2020-03-13 08:56:58 -05:00
if ( ! can_assume ( VALID_INPUT ) & & ! re )
2018-09-13 08:59:25 -05:00
return - FDT_ERR_BADOFFSET ;
2021-02-03 15:26:03 -06:00
* address = fdt64_ld_ ( & re - > address ) ;
* size = fdt64_ld_ ( & re - > size ) ;
2007-12-10 14:28:39 +11:00
return 0 ;
}
int fdt_num_mem_rsv ( const void * fdt )
{
2018-09-13 08:59:25 -05:00
int i ;
const struct fdt_reserve_entry * re ;
2007-12-10 14:28:39 +11:00
2018-09-13 08:59:25 -05:00
for ( i = 0 ; ( re = fdt_mem_rsv ( fdt , i ) ) ! = NULL ; i + + ) {
2021-02-03 15:26:03 -06:00
if ( fdt64_ld_ ( & re - > size ) = = 0 )
2018-09-13 08:59:25 -05:00
return i ;
}
return - FDT_ERR_TRUNCATED ;
2007-12-10 14:28:39 +11:00
}
2018-02-27 17:40:38 -06:00
static int nextprop_ ( const void * fdt , int offset )
2012-09-28 21:25:59 +00:00
{
uint32_t tag ;
int nextoffset ;
do {
tag = fdt_next_tag ( fdt , offset , & nextoffset ) ;
switch ( tag ) {
case FDT_END :
if ( nextoffset > = 0 )
return - FDT_ERR_BADSTRUCTURE ;
else
return nextoffset ;
case FDT_PROP :
return offset ;
}
offset = nextoffset ;
} while ( tag = = FDT_NOP ) ;
return - FDT_ERR_NOTFOUND ;
}
2008-08-07 12:24:17 +10:00
int fdt_subnode_offset_namelen ( const void * fdt , int offset ,
2007-12-10 14:28:39 +11:00
const char * name , int namelen )
{
2008-08-07 12:24:17 +10:00
int depth ;
2007-12-10 14:28:39 +11:00
2018-09-13 08:59:25 -05:00
FDT_RO_PROBE ( fdt ) ;
2007-12-10 14:28:39 +11:00
2012-09-28 21:25:59 +00:00
for ( depth = 0 ;
( offset > = 0 ) & & ( depth > = 0 ) ;
offset = fdt_next_node ( fdt , offset , & depth ) )
if ( ( depth = = 1 )
2018-02-27 17:40:38 -06:00
& & fdt_nodename_eq_ ( fdt , offset , name , namelen ) )
2008-08-07 12:24:17 +10:00
return offset ;
2007-12-10 14:28:39 +11:00
2012-09-28 21:25:59 +00:00
if ( depth < 0 )
2008-10-30 16:37:05 +00:00
return - FDT_ERR_NOTFOUND ;
2012-09-28 21:25:59 +00:00
return offset ; /* error */
2007-12-10 14:28:39 +11:00
}
int fdt_subnode_offset ( const void * fdt , int parentoffset ,
const char * name )
{
return fdt_subnode_offset_namelen ( fdt , parentoffset , name , strlen ( name ) ) ;
}
2015-04-29 16:00:05 -05:00
int fdt_path_offset_namelen ( const void * fdt , const char * path , int namelen )
2007-12-10 14:28:39 +11:00
{
2015-04-29 16:00:05 -05:00
const char * end = path + namelen ;
2007-12-10 14:28:39 +11:00
const char * p = path ;
int offset = 0 ;
2018-09-13 08:59:25 -05:00
FDT_RO_PROBE ( fdt ) ;
2007-12-10 14:28:39 +11:00
2012-09-28 21:25:59 +00:00
/* see if we have an alias */
if ( * path ! = ' / ' ) {
2015-04-29 16:00:05 -05:00
const char * q = memchr ( path , ' / ' , end - p ) ;
2012-09-28 21:25:59 +00:00
if ( ! q )
q = end ;
p = fdt_get_alias_namelen ( fdt , p , q - p ) ;
if ( ! p )
return - FDT_ERR_BADPATH ;
offset = fdt_path_offset ( fdt , p ) ;
p = q ;
}
2007-12-10 14:28:39 +11:00
2015-04-29 16:00:05 -05:00
while ( p < end ) {
2007-12-10 14:28:39 +11:00
const char * q ;
2015-04-29 16:00:05 -05:00
while ( * p = = ' / ' ) {
2007-12-10 14:28:39 +11:00
p + + ;
2015-04-29 16:00:05 -05:00
if ( p = = end )
return offset ;
}
q = memchr ( p , ' / ' , end - p ) ;
2007-12-10 14:28:39 +11:00
if ( ! q )
q = end ;
offset = fdt_subnode_offset_namelen ( fdt , offset , p , q - p ) ;
if ( offset < 0 )
return offset ;
p = q ;
}
return offset ;
}
2015-04-29 16:00:05 -05:00
int fdt_path_offset ( const void * fdt , const char * path )
{
return fdt_path_offset_namelen ( fdt , path , strlen ( path ) ) ;
}
2007-12-10 14:28:39 +11:00
const char * fdt_get_name ( const void * fdt , int nodeoffset , int * len )
{
2018-02-27 17:40:38 -06:00
const struct fdt_node_header * nh = fdt_offset_ptr_ ( fdt , nodeoffset ) ;
const char * nameptr ;
2007-12-10 14:28:39 +11:00
int err ;
2019-12-26 15:36:47 -07:00
if ( ( ( err = fdt_ro_probe_ ( fdt ) ) < 0 )
2018-02-27 17:40:38 -06:00
| | ( ( err = fdt_check_node_offset_ ( fdt , nodeoffset ) ) < 0 ) )
2008-08-07 12:24:17 +10:00
goto fail ;
2007-12-10 14:28:39 +11:00
2018-02-27 17:40:38 -06:00
nameptr = nh - > name ;
2020-03-13 08:56:58 -05:00
if ( ! can_assume ( LATEST ) & & fdt_version ( fdt ) < 0x10 ) {
2018-02-27 17:40:38 -06:00
/*
* For old FDT versions , match the naming conventions of V16 :
* give only the leaf name ( after all / ) . The actual tree
* contents are loosely checked .
*/
const char * leaf ;
leaf = strrchr ( nameptr , ' / ' ) ;
if ( leaf = = NULL ) {
err = - FDT_ERR_BADSTRUCTURE ;
goto fail ;
}
nameptr = leaf + 1 ;
}
2007-12-10 14:28:39 +11:00
if ( len )
2018-02-27 17:40:38 -06:00
* len = strlen ( nameptr ) ;
2007-12-10 14:28:39 +11:00
2018-02-27 17:40:38 -06:00
return nameptr ;
2007-12-10 14:28:39 +11:00
fail :
if ( len )
* len = err ;
return NULL ;
}
2012-09-28 21:25:59 +00:00
int fdt_first_property_offset ( const void * fdt , int nodeoffset )
{
int offset ;
2018-02-27 17:40:38 -06:00
if ( ( offset = fdt_check_node_offset_ ( fdt , nodeoffset ) ) < 0 )
2012-09-28 21:25:59 +00:00
return offset ;
2018-02-27 17:40:38 -06:00
return nextprop_ ( fdt , offset ) ;
2012-09-28 21:25:59 +00:00
}
int fdt_next_property_offset ( const void * fdt , int offset )
{
2018-02-27 17:40:38 -06:00
if ( ( offset = fdt_check_prop_offset_ ( fdt , offset ) ) < 0 )
2012-09-28 21:25:59 +00:00
return offset ;
2018-02-27 17:40:38 -06:00
return nextprop_ ( fdt , offset ) ;
2012-09-28 21:25:59 +00:00
}
2018-02-27 17:40:38 -06:00
static const struct fdt_property * fdt_get_property_by_offset_ ( const void * fdt ,
int offset ,
int * lenp )
2007-12-10 14:28:39 +11:00
{
int err ;
2012-09-28 21:25:59 +00:00
const struct fdt_property * prop ;
2007-12-10 14:28:39 +11:00
2020-03-13 08:56:58 -05:00
if ( ! can_assume ( VALID_INPUT ) & &
( err = fdt_check_prop_offset_ ( fdt , offset ) ) < 0 ) {
2012-09-28 21:25:59 +00:00
if ( lenp )
* lenp = err ;
return NULL ;
}
2007-12-10 14:28:39 +11:00
2018-02-27 17:40:38 -06:00
prop = fdt_offset_ptr_ ( fdt , offset ) ;
2007-12-10 14:28:39 +11:00
2012-09-28 21:25:59 +00:00
if ( lenp )
2021-02-03 15:26:03 -06:00
* lenp = fdt32_ld_ ( & prop - > len ) ;
2007-12-10 14:28:39 +11:00
2012-09-28 21:25:59 +00:00
return prop ;
}
2007-12-10 14:28:39 +11:00
2018-02-27 17:40:38 -06:00
const struct fdt_property * fdt_get_property_by_offset ( const void * fdt ,
int offset ,
int * lenp )
{
/* Prior to version 16, properties may need realignment
* and this API does not work . fdt_getprop_ * ( ) will , however . */
2020-03-13 08:56:58 -05:00
if ( ! can_assume ( LATEST ) & & fdt_version ( fdt ) < 0x10 ) {
2018-02-27 17:40:38 -06:00
if ( lenp )
* lenp = - FDT_ERR_BADVERSION ;
return NULL ;
}
return fdt_get_property_by_offset_ ( fdt , offset , lenp ) ;
}
static const struct fdt_property * fdt_get_property_namelen_ ( const void * fdt ,
int offset ,
const char * name ,
int namelen ,
int * lenp ,
int * poffset )
2012-09-28 21:25:59 +00:00
{
for ( offset = fdt_first_property_offset ( fdt , offset ) ;
( offset > = 0 ) ;
( offset = fdt_next_property_offset ( fdt , offset ) ) ) {
const struct fdt_property * prop ;
2007-12-10 14:28:39 +11:00
2020-03-13 08:56:58 -05:00
prop = fdt_get_property_by_offset_ ( fdt , offset , lenp ) ;
if ( ! can_assume ( LIBFDT_FLAWLESS ) & & ! prop ) {
2012-09-28 21:25:59 +00:00
offset = - FDT_ERR_INTERNAL ;
break ;
2007-12-10 14:28:39 +11:00
}
2021-02-03 15:26:03 -06:00
if ( fdt_string_eq_ ( fdt , fdt32_ld_ ( & prop - > nameoff ) ,
2018-02-27 17:40:38 -06:00
name , namelen ) ) {
if ( poffset )
* poffset = offset ;
2012-09-28 21:25:59 +00:00
return prop ;
2018-02-27 17:40:38 -06:00
}
2012-09-28 21:25:59 +00:00
}
2007-12-10 14:28:39 +11:00
if ( lenp )
2012-09-28 21:25:59 +00:00
* lenp = offset ;
2007-12-10 14:28:39 +11:00
return NULL ;
}
2018-02-27 17:40:38 -06:00
const struct fdt_property * fdt_get_property_namelen ( const void * fdt ,
int offset ,
const char * name ,
int namelen , int * lenp )
{
/* Prior to version 16, properties may need realignment
* and this API does not work . fdt_getprop_ * ( ) will , however . */
2020-03-13 08:56:58 -05:00
if ( ! can_assume ( LATEST ) & & fdt_version ( fdt ) < 0x10 ) {
2018-02-27 17:40:38 -06:00
if ( lenp )
* lenp = - FDT_ERR_BADVERSION ;
return NULL ;
}
return fdt_get_property_namelen_ ( fdt , offset , name , namelen , lenp ,
NULL ) ;
}
2012-09-28 21:25:59 +00:00
const struct fdt_property * fdt_get_property ( const void * fdt ,
int nodeoffset ,
const char * name , int * lenp )
{
return fdt_get_property_namelen ( fdt , nodeoffset , name ,
strlen ( name ) , lenp ) ;
}
const void * fdt_getprop_namelen ( const void * fdt , int nodeoffset ,
const char * name , int namelen , int * lenp )
2007-12-10 14:28:39 +11:00
{
2018-02-27 17:40:38 -06:00
int poffset ;
2007-12-10 14:28:39 +11:00
const struct fdt_property * prop ;
2018-02-27 17:40:38 -06:00
prop = fdt_get_property_namelen_ ( fdt , nodeoffset , name , namelen , lenp ,
& poffset ) ;
2017-10-03 11:37:04 -05:00
if ( ! prop )
2007-12-10 14:28:39 +11:00
return NULL ;
2018-02-27 17:40:38 -06:00
/* Handle realignment */
2020-03-13 08:56:58 -05:00
if ( ! can_assume ( LATEST ) & & fdt_version ( fdt ) < 0x10 & &
2021-02-03 15:26:03 -06:00
( poffset + sizeof ( * prop ) ) % 8 & & fdt32_ld_ ( & prop - > len ) > = 8 )
2018-02-27 17:40:38 -06:00
return prop - > data + 4 ;
2007-12-10 14:28:39 +11:00
return prop - > data ;
}
2012-09-28 21:25:59 +00:00
const void * fdt_getprop_by_offset ( const void * fdt , int offset ,
const char * * namep , int * lenp )
{
const struct fdt_property * prop ;
2018-02-27 17:40:38 -06:00
prop = fdt_get_property_by_offset_ ( fdt , offset , lenp ) ;
2012-09-28 21:25:59 +00:00
if ( ! prop )
return NULL ;
2018-09-13 08:59:25 -05:00
if ( namep ) {
const char * name ;
int namelen ;
2020-03-13 08:56:58 -05:00
if ( ! can_assume ( VALID_INPUT ) ) {
2021-02-03 15:26:03 -06:00
name = fdt_get_string ( fdt , fdt32_ld_ ( & prop - > nameoff ) ,
2020-03-13 08:56:58 -05:00
& namelen ) ;
2022-11-01 12:54:44 -05:00
* namep = name ;
2020-03-13 08:56:58 -05:00
if ( ! name ) {
if ( lenp )
* lenp = namelen ;
return NULL ;
}
} else {
2021-02-03 15:26:03 -06:00
* namep = fdt_string ( fdt , fdt32_ld_ ( & prop - > nameoff ) ) ;
2018-09-13 08:59:25 -05:00
}
}
2018-02-27 17:40:38 -06:00
/* Handle realignment */
2020-03-13 08:56:58 -05:00
if ( ! can_assume ( LATEST ) & & fdt_version ( fdt ) < 0x10 & &
2021-02-03 15:26:03 -06:00
( offset + sizeof ( * prop ) ) % 8 & & fdt32_ld_ ( & prop - > len ) > = 8 )
2018-02-27 17:40:38 -06:00
return prop - > data + 4 ;
2012-09-28 21:25:59 +00:00
return prop - > data ;
}
const void * fdt_getprop ( const void * fdt , int nodeoffset ,
const char * name , int * lenp )
{
return fdt_getprop_namelen ( fdt , nodeoffset , name , strlen ( name ) , lenp ) ;
}
2007-12-10 14:28:39 +11:00
uint32_t fdt_get_phandle ( const void * fdt , int nodeoffset )
{
2015-04-29 16:00:05 -05:00
const fdt32_t * php ;
2007-12-10 14:28:39 +11:00
int len ;
2012-09-28 21:25:59 +00:00
/* FIXME: This is a bit sub-optimal, since we potentially scan
* over all the properties twice . */
php = fdt_getprop ( fdt , nodeoffset , " phandle " , & len ) ;
if ( ! php | | ( len ! = sizeof ( * php ) ) ) {
php = fdt_getprop ( fdt , nodeoffset , " linux,phandle " , & len ) ;
if ( ! php | | ( len ! = sizeof ( * php ) ) )
return 0 ;
}
2007-12-10 14:28:39 +11:00
2021-02-03 15:26:03 -06:00
return fdt32_ld_ ( php ) ;
2007-12-10 14:28:39 +11:00
}
2012-09-28 21:25:59 +00:00
const char * fdt_get_alias_namelen ( const void * fdt ,
const char * name , int namelen )
{
int aliasoffset ;
aliasoffset = fdt_path_offset ( fdt , " /aliases " ) ;
if ( aliasoffset < 0 )
return NULL ;
return fdt_getprop_namelen ( fdt , aliasoffset , name , namelen , NULL ) ;
}
const char * fdt_get_alias ( const void * fdt , const char * name )
{
return fdt_get_alias_namelen ( fdt , name , strlen ( name ) ) ;
}
2007-12-10 14:28:39 +11:00
int fdt_get_path ( const void * fdt , int nodeoffset , char * buf , int buflen )
{
2008-08-07 12:24:17 +10:00
int pdepth = 0 , p = 0 ;
int offset , depth , namelen ;
2007-12-10 14:28:39 +11:00
const char * name ;
2018-09-13 08:59:25 -05:00
FDT_RO_PROBE ( fdt ) ;
2007-12-10 14:28:39 +11:00
if ( buflen < 2 )
return - FDT_ERR_NOSPACE ;
2008-08-07 12:24:17 +10:00
for ( offset = 0 , depth = 0 ;
( offset > = 0 ) & & ( offset < = nodeoffset ) ;
offset = fdt_next_node ( fdt , offset , & depth ) ) {
while ( pdepth > depth ) {
do {
p - - ;
} while ( buf [ p - 1 ] ! = ' / ' ) ;
pdepth - - ;
}
2012-09-28 21:25:59 +00:00
if ( pdepth > = depth ) {
name = fdt_get_name ( fdt , offset , & namelen ) ;
if ( ! name )
return namelen ;
if ( ( p + namelen + 1 ) < = buflen ) {
memcpy ( buf + p , name , namelen ) ;
p + = namelen ;
buf [ p + + ] = ' / ' ;
pdepth + + ;
}
2008-08-07 12:24:17 +10:00
}
2007-12-10 14:28:39 +11:00
2008-08-07 12:24:17 +10:00
if ( offset = = nodeoffset ) {
if ( pdepth < ( depth + 1 ) )
return - FDT_ERR_NOSPACE ;
2007-12-10 14:28:39 +11:00
2008-08-07 12:24:17 +10:00
if ( p > 1 ) /* special case so that root path is "/", not "" */
p - - ;
buf [ p ] = ' \0 ' ;
2012-09-28 21:25:59 +00:00
return 0 ;
2007-12-10 14:28:39 +11:00
}
}
2008-08-07 12:24:17 +10:00
if ( ( offset = = - FDT_ERR_NOTFOUND ) | | ( offset > = 0 ) )
return - FDT_ERR_BADOFFSET ;
else if ( offset = = - FDT_ERR_BADOFFSET )
return - FDT_ERR_BADSTRUCTURE ;
2007-12-10 14:28:39 +11:00
2008-08-07 12:24:17 +10:00
return offset ; /* error from fdt_next_node() */
2007-12-10 14:28:39 +11:00
}
int fdt_supernode_atdepth_offset ( const void * fdt , int nodeoffset ,
int supernodedepth , int * nodedepth )
{
2008-08-07 12:24:17 +10:00
int offset , depth ;
2007-12-10 14:28:39 +11:00
int supernodeoffset = - FDT_ERR_INTERNAL ;
2018-09-13 08:59:25 -05:00
FDT_RO_PROBE ( fdt ) ;
2007-12-10 14:28:39 +11:00
if ( supernodedepth < 0 )
return - FDT_ERR_NOTFOUND ;
2008-08-07 12:24:17 +10:00
for ( offset = 0 , depth = 0 ;
( offset > = 0 ) & & ( offset < = nodeoffset ) ;
offset = fdt_next_node ( fdt , offset , & depth ) ) {
if ( depth = = supernodedepth )
supernodeoffset = offset ;
2007-12-10 14:28:39 +11:00
2008-08-07 12:24:17 +10:00
if ( offset = = nodeoffset ) {
if ( nodedepth )
* nodedepth = depth ;
2007-12-10 14:28:39 +11:00
2008-08-07 12:24:17 +10:00
if ( supernodedepth > depth )
return - FDT_ERR_NOTFOUND ;
else
return supernodeoffset ;
2007-12-10 14:28:39 +11:00
}
2008-08-07 12:24:17 +10:00
}
2007-12-10 14:28:39 +11:00
2020-03-13 08:56:58 -05:00
if ( ! can_assume ( VALID_INPUT ) ) {
if ( ( offset = = - FDT_ERR_NOTFOUND ) | | ( offset > = 0 ) )
return - FDT_ERR_BADOFFSET ;
else if ( offset = = - FDT_ERR_BADOFFSET )
return - FDT_ERR_BADSTRUCTURE ;
}
2007-12-10 14:28:39 +11:00
2008-08-07 12:24:17 +10:00
return offset ; /* error from fdt_next_node() */
2007-12-10 14:28:39 +11:00
}
int fdt_node_depth ( const void * fdt , int nodeoffset )
{
int nodedepth ;
int err ;
err = fdt_supernode_atdepth_offset ( fdt , nodeoffset , 0 , & nodedepth ) ;
if ( err )
2020-03-13 08:56:58 -05:00
return ( can_assume ( LIBFDT_FLAWLESS ) | | err < 0 ) ? err :
- FDT_ERR_INTERNAL ;
2007-12-10 14:28:39 +11:00
return nodedepth ;
}
int fdt_parent_offset ( const void * fdt , int nodeoffset )
{
int nodedepth = fdt_node_depth ( fdt , nodeoffset ) ;
if ( nodedepth < 0 )
return nodedepth ;
return fdt_supernode_atdepth_offset ( fdt , nodeoffset ,
nodedepth - 1 , NULL ) ;
}
int fdt_node_offset_by_prop_value ( const void * fdt , int startoffset ,
const char * propname ,
const void * propval , int proplen )
{
2008-08-07 12:24:17 +10:00
int offset ;
2007-12-10 14:28:39 +11:00
const void * val ;
int len ;
2018-09-13 08:59:25 -05:00
FDT_RO_PROBE ( fdt ) ;
2007-12-10 14:28:39 +11:00
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_getprop ( ) , then if that didn ' t
* find what we want , we scan over them again making our way
* to the next node . Still it ' s the easiest to implement
* approach ; performance can come later . */
2008-08-07 12:24:17 +10:00
for ( offset = fdt_next_node ( fdt , startoffset , NULL ) ;
offset > = 0 ;
offset = fdt_next_node ( fdt , offset , NULL ) ) {
val = fdt_getprop ( fdt , offset , propname , & len ) ;
if ( val & & ( len = = proplen )
& & ( memcmp ( val , propval , len ) = = 0 ) )
return offset ;
}
2007-12-10 14:28:39 +11:00
2008-08-07 12:24:17 +10:00
return offset ; /* error from fdt_next_node() */
2007-12-10 14:28:39 +11:00
}
int fdt_node_offset_by_phandle ( const void * fdt , uint32_t phandle )
{
2012-09-28 21:25:59 +00:00
int offset ;
2020-10-12 09:58:15 -05:00
if ( ( phandle = = 0 ) | | ( phandle = = ~ 0U ) )
2007-12-10 14:28:39 +11:00
return - FDT_ERR_BADPHANDLE ;
2012-09-28 21:25:59 +00:00
2018-09-13 08:59:25 -05:00
FDT_RO_PROBE ( fdt ) ;
2012-09-28 21:25:59 +00:00
/* FIXME: The algorithm here is pretty horrible: we
* potentially scan each property of a node in
* fdt_get_phandle ( ) , then if that didn ' t find what
* we want , we scan over them again making our way to the next
* node . Still it ' s the easiest to implement approach ;
* performance can come later . */
for ( offset = fdt_next_node ( fdt , - 1 , NULL ) ;
offset > = 0 ;
offset = fdt_next_node ( fdt , offset , NULL ) ) {
if ( fdt_get_phandle ( fdt , offset ) = = phandle )
return offset ;
}
return offset ; /* error from fdt_next_node() */
2007-12-10 14:28:39 +11:00
}
2015-04-29 16:00:05 -05:00
int fdt_stringlist_contains ( const char * strlist , int listlen , const char * str )
2007-12-10 14:28:39 +11:00
{
int len = strlen ( str ) ;
2008-08-07 12:24:17 +10:00
const char * p ;
2007-12-10 14:28:39 +11:00
while ( listlen > = len ) {
if ( memcmp ( str , strlist , len + 1 ) = = 0 )
return 1 ;
p = memchr ( strlist , ' \0 ' , listlen ) ;
if ( ! p )
return 0 ; /* malformed strlist.. */
listlen - = ( p - strlist ) + 1 ;
strlist = p + 1 ;
}
return 0 ;
}
2016-01-26 09:04:11 -06:00
int fdt_stringlist_count ( const void * fdt , int nodeoffset , const char * property )
{
const char * list , * end ;
int length , count = 0 ;
list = fdt_getprop ( fdt , nodeoffset , property , & length ) ;
if ( ! list )
2017-01-04 10:45:20 -06:00
return length ;
2016-01-26 09:04:11 -06:00
end = list + length ;
while ( list < end ) {
length = strnlen ( list , end - list ) + 1 ;
/* Abort if the last string isn't properly NUL-terminated. */
if ( list + length > end )
return - FDT_ERR_BADVALUE ;
list + = length ;
count + + ;
}
return count ;
}
int fdt_stringlist_search ( const void * fdt , int nodeoffset , const char * property ,
const char * string )
{
int length , len , idx = 0 ;
const char * list , * end ;
list = fdt_getprop ( fdt , nodeoffset , property , & length ) ;
if ( ! list )
2017-01-04 10:45:20 -06:00
return length ;
2016-01-26 09:04:11 -06:00
len = strlen ( string ) + 1 ;
end = list + length ;
while ( list < end ) {
length = strnlen ( list , end - list ) + 1 ;
/* Abort if the last string isn't properly NUL-terminated. */
if ( list + length > end )
return - FDT_ERR_BADVALUE ;
if ( length = = len & & memcmp ( list , string , length ) = = 0 )
return idx ;
list + = length ;
idx + + ;
}
return - FDT_ERR_NOTFOUND ;
}
const char * fdt_stringlist_get ( const void * fdt , int nodeoffset ,
const char * property , int idx ,
int * lenp )
{
const char * list , * end ;
int length ;
list = fdt_getprop ( fdt , nodeoffset , property , & length ) ;
if ( ! list ) {
if ( lenp )
* lenp = length ;
return NULL ;
}
end = list + length ;
while ( list < end ) {
length = strnlen ( list , end - list ) + 1 ;
/* Abort if the last string isn't properly NUL-terminated. */
if ( list + length > end ) {
if ( lenp )
* lenp = - FDT_ERR_BADVALUE ;
return NULL ;
}
if ( idx = = 0 ) {
if ( lenp )
* lenp = length - 1 ;
return list ;
}
list + = length ;
idx - - ;
}
if ( lenp )
* lenp = - FDT_ERR_NOTFOUND ;
return NULL ;
}
2007-12-10 14:28:39 +11:00
int fdt_node_check_compatible ( const void * fdt , int nodeoffset ,
const char * compatible )
{
const void * prop ;
int len ;
prop = fdt_getprop ( fdt , nodeoffset , " compatible " , & len ) ;
if ( ! prop )
return len ;
2016-03-04 08:56:58 -06:00
return ! fdt_stringlist_contains ( prop , len , compatible ) ;
2007-12-10 14:28:39 +11:00
}
int fdt_node_offset_by_compatible ( const void * fdt , int startoffset ,
const char * compatible )
{
2008-08-07 12:24:17 +10:00
int offset , err ;
2007-12-10 14:28:39 +11:00
2018-09-13 08:59:25 -05:00
FDT_RO_PROBE ( fdt ) ;
2007-12-10 14:28:39 +11:00
/* FIXME: The algorithm here is pretty horrible: we scan each
* property of a node in fdt_node_check_compatible ( ) , then if
* that didn ' t find what we want , we scan over them again
* making our way to the next node . Still it ' s the easiest to
* implement approach ; performance can come later . */
2008-08-07 12:24:17 +10:00
for ( offset = fdt_next_node ( fdt , startoffset , NULL ) ;
offset > = 0 ;
offset = fdt_next_node ( fdt , offset , NULL ) ) {
err = fdt_node_check_compatible ( fdt , offset , compatible ) ;
if ( ( err < 0 ) & & ( err ! = - FDT_ERR_NOTFOUND ) )
return err ;
else if ( err = = 0 )
return offset ;
}
2007-12-10 14:28:39 +11:00
2008-08-07 12:24:17 +10:00
return offset ; /* error from fdt_next_node() */
2007-12-10 14:28:39 +11:00
}