2007-05-01 10:26:07 +04:00
/*
* Procedures for creating , accessing and interpreting the device tree .
*
* Paul Mackerras August 1996.
* Copyright ( C ) 1996 - 2005 Paul Mackerras .
*
* Adapted for 64 bit PowerPC by Dave Engebretsen and Peter Bergner .
* { engebret | bergner } @ us . ibm . com
*
* Adapted for sparc and sparc64 by David S . Miller davem @ davemloft . net
*
* Reconsolidated from arch / x / kernel / prom . c by Stephen Rothwell .
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/module.h>
# include <linux/of.h>
2007-04-24 10:46:53 +04:00
# include <linux/spinlock.h>
2007-04-24 11:57:33 +04:00
struct device_node * allnodes ;
2007-04-24 10:46:53 +04:00
/* use when traversing tree through the allnext, child, sibling,
* or parent members of struct device_node .
*/
DEFINE_RWLOCK ( devtree_lock ) ;
2007-05-01 10:26:07 +04:00
int of_n_addr_cells ( struct device_node * np )
{
const int * ip ;
do {
if ( np - > parent )
np = np - > parent ;
ip = of_get_property ( np , " #address-cells " , NULL ) ;
if ( ip )
return * ip ;
} while ( np - > parent ) ;
/* No #address-cells property for the root node */
return OF_ROOT_NODE_ADDR_CELLS_DEFAULT ;
}
EXPORT_SYMBOL ( of_n_addr_cells ) ;
int of_n_size_cells ( struct device_node * np )
{
const int * ip ;
do {
if ( np - > parent )
np = np - > parent ;
ip = of_get_property ( np , " #size-cells " , NULL ) ;
if ( ip )
return * ip ;
} while ( np - > parent ) ;
/* No #size-cells property for the root node */
return OF_ROOT_NODE_SIZE_CELLS_DEFAULT ;
}
EXPORT_SYMBOL ( of_n_size_cells ) ;
2007-04-24 10:46:53 +04:00
struct property * of_find_property ( const struct device_node * np ,
const char * name ,
int * lenp )
{
struct property * pp ;
2008-05-07 23:19:59 +04:00
if ( ! np )
return NULL ;
2007-04-24 10:46:53 +04:00
read_lock ( & devtree_lock ) ;
for ( pp = np - > properties ; pp ! = 0 ; pp = pp - > next ) {
if ( of_prop_cmp ( pp - > name , name ) = = 0 ) {
if ( lenp ! = 0 )
* lenp = pp - > length ;
break ;
}
}
read_unlock ( & devtree_lock ) ;
return pp ;
}
EXPORT_SYMBOL ( of_find_property ) ;
2007-05-01 10:26:07 +04:00
/*
* Find a property with a given name for a given node
* and return the value .
*/
const void * of_get_property ( const struct device_node * np , const char * name ,
int * lenp )
{
struct property * pp = of_find_property ( np , name , lenp ) ;
return pp ? pp - > value : NULL ;
}
EXPORT_SYMBOL ( of_get_property ) ;
2007-05-01 10:29:19 +04:00
/** Checks if the given "compat" string matches one of the strings in
* the device ' s " compatible " property
*/
int of_device_is_compatible ( const struct device_node * device ,
const char * compat )
{
const char * cp ;
int cplen , l ;
cp = of_get_property ( device , " compatible " , & cplen ) ;
if ( cp = = NULL )
return 0 ;
while ( cplen > 0 ) {
if ( of_compat_cmp ( cp , compat , strlen ( compat ) ) = = 0 )
return 1 ;
l = strlen ( cp ) + 1 ;
cp + = l ;
cplen - = l ;
}
return 0 ;
}
EXPORT_SYMBOL ( of_device_is_compatible ) ;
2007-04-24 11:16:16 +04:00
2008-03-26 16:33:14 +03:00
/**
* of_device_is_available - check if a device is available for use
*
* @ device : Node to check for availability
*
* Returns 1 if the status property is absent or set to " okay " or " ok " ,
* 0 otherwise
*/
int of_device_is_available ( const struct device_node * device )
{
const char * status ;
int statlen ;
status = of_get_property ( device , " status " , & statlen ) ;
if ( status = = NULL )
return 1 ;
if ( statlen > 0 ) {
if ( ! strcmp ( status , " okay " ) | | ! strcmp ( status , " ok " ) )
return 1 ;
}
return 0 ;
}
EXPORT_SYMBOL ( of_device_is_available ) ;
2007-04-24 11:16:16 +04:00
/**
* of_get_parent - Get a node ' s parent if any
* @ node : Node to get parent
*
* Returns a node pointer with refcount incremented , use
* of_node_put ( ) on it when done .
*/
struct device_node * of_get_parent ( const struct device_node * node )
{
struct device_node * np ;
if ( ! node )
return NULL ;
read_lock ( & devtree_lock ) ;
np = of_node_get ( node - > parent ) ;
read_unlock ( & devtree_lock ) ;
return np ;
}
EXPORT_SYMBOL ( of_get_parent ) ;
2007-04-24 11:21:29 +04:00
2007-10-26 10:54:31 +04:00
/**
* of_get_next_parent - Iterate to a node ' s parent
* @ node : Node to get parent of
*
* This is like of_get_parent ( ) except that it drops the
* refcount on the passed node , making it suitable for iterating
* through a node ' s parents .
*
* Returns a node pointer with refcount incremented , use
* of_node_put ( ) on it when done .
*/
struct device_node * of_get_next_parent ( struct device_node * node )
{
struct device_node * parent ;
if ( ! node )
return NULL ;
read_lock ( & devtree_lock ) ;
parent = of_node_get ( node - > parent ) ;
of_node_put ( node ) ;
read_unlock ( & devtree_lock ) ;
return parent ;
}
2007-04-24 11:21:29 +04:00
/**
* of_get_next_child - Iterate a node childs
* @ node : parent node
* @ prev : previous child of the parent node , or NULL to get first
*
* Returns a node pointer with refcount incremented , use
* of_node_put ( ) on it when done .
*/
struct device_node * of_get_next_child ( const struct device_node * node ,
struct device_node * prev )
{
struct device_node * next ;
read_lock ( & devtree_lock ) ;
next = prev ? prev - > sibling : node - > child ;
for ( ; next ; next = next - > sibling )
if ( of_node_get ( next ) )
break ;
of_node_put ( prev ) ;
read_unlock ( & devtree_lock ) ;
return next ;
}
EXPORT_SYMBOL ( of_get_next_child ) ;
2007-04-24 11:57:33 +04:00
/**
* of_find_node_by_path - Find a node matching a full OF path
* @ path : The full path to match
*
* Returns a node pointer with refcount incremented , use
* of_node_put ( ) on it when done .
*/
struct device_node * of_find_node_by_path ( const char * path )
{
struct device_node * np = allnodes ;
read_lock ( & devtree_lock ) ;
for ( ; np ; np = np - > allnext ) {
if ( np - > full_name & & ( of_node_cmp ( np - > full_name , path ) = = 0 )
& & of_node_get ( np ) )
break ;
}
read_unlock ( & devtree_lock ) ;
return np ;
}
EXPORT_SYMBOL ( of_find_node_by_path ) ;
/**
* of_find_node_by_name - Find a node by its " name " property
* @ from : The node to start searching from or NULL , the node
* you pass will not be searched , only the next one
* will ; typically , you pass what the previous call
* returned . of_node_put ( ) will be called on it
* @ name : The name string to match against
*
* Returns a node pointer with refcount incremented , use
* of_node_put ( ) on it when done .
*/
struct device_node * of_find_node_by_name ( struct device_node * from ,
const char * name )
{
struct device_node * np ;
read_lock ( & devtree_lock ) ;
np = from ? from - > allnext : allnodes ;
for ( ; np ; np = np - > allnext )
if ( np - > name & & ( of_node_cmp ( np - > name , name ) = = 0 )
& & of_node_get ( np ) )
break ;
of_node_put ( from ) ;
read_unlock ( & devtree_lock ) ;
return np ;
}
EXPORT_SYMBOL ( of_find_node_by_name ) ;
/**
* of_find_node_by_type - Find a node by its " device_type " property
* @ from : The node to start searching from , or NULL to start searching
* the entire device tree . The node you pass will not be
* searched , only the next one will ; typically , you pass
* what the previous call returned . of_node_put ( ) will be
* called on from for you .
* @ type : The type string to match against
*
* Returns a node pointer with refcount incremented , use
* of_node_put ( ) on it when done .
*/
struct device_node * of_find_node_by_type ( struct device_node * from ,
const char * type )
{
struct device_node * np ;
read_lock ( & devtree_lock ) ;
np = from ? from - > allnext : allnodes ;
for ( ; np ; np = np - > allnext )
if ( np - > type & & ( of_node_cmp ( np - > type , type ) = = 0 )
& & of_node_get ( np ) )
break ;
of_node_put ( from ) ;
read_unlock ( & devtree_lock ) ;
return np ;
}
EXPORT_SYMBOL ( of_find_node_by_type ) ;
/**
* of_find_compatible_node - Find a node based on type and one of the
* tokens in its " compatible " property
* @ from : The node to start searching from or NULL , the node
* you pass will not be searched , only the next one
* will ; typically , you pass what the previous call
* returned . of_node_put ( ) will be called on it
* @ type : The type string to match " device_type " or NULL to ignore
* @ compatible : The string to match to one of the tokens in the device
* " compatible " list .
*
* Returns a node pointer with refcount incremented , use
* of_node_put ( ) on it when done .
*/
struct device_node * of_find_compatible_node ( struct device_node * from ,
const char * type , const char * compatible )
{
struct device_node * np ;
read_lock ( & devtree_lock ) ;
np = from ? from - > allnext : allnodes ;
for ( ; np ; np = np - > allnext ) {
if ( type
& & ! ( np - > type & & ( of_node_cmp ( np - > type , type ) = = 0 ) ) )
continue ;
if ( of_device_is_compatible ( np , compatible ) & & of_node_get ( np ) )
break ;
}
of_node_put ( from ) ;
read_unlock ( & devtree_lock ) ;
return np ;
}
EXPORT_SYMBOL ( of_find_compatible_node ) ;
2008-01-08 22:20:40 +03:00
/**
* of_match_node - Tell if an device_node has a matching of_match structure
* @ matches : array of of device match structures to search in
* @ node : the of device structure to match against
*
* Low level utility function used by device matching .
*/
const struct of_device_id * of_match_node ( const struct of_device_id * matches ,
const struct device_node * node )
{
while ( matches - > name [ 0 ] | | matches - > type [ 0 ] | | matches - > compatible [ 0 ] ) {
int match = 1 ;
if ( matches - > name [ 0 ] )
match & = node - > name
& & ! strcmp ( matches - > name , node - > name ) ;
if ( matches - > type [ 0 ] )
match & = node - > type
& & ! strcmp ( matches - > type , node - > type ) ;
if ( matches - > compatible [ 0 ] )
match & = of_device_is_compatible ( node ,
matches - > compatible ) ;
if ( match )
return matches ;
matches + + ;
}
return NULL ;
}
EXPORT_SYMBOL ( of_match_node ) ;
/**
* of_find_matching_node - Find a node based on an of_device_id match
* table .
* @ from : The node to start searching from or NULL , the node
* you pass will not be searched , only the next one
* will ; typically , you pass what the previous call
* returned . of_node_put ( ) will be called on it
* @ matches : array of of device match structures to search in
*
* Returns a node pointer with refcount incremented , use
* of_node_put ( ) on it when done .
*/
struct device_node * of_find_matching_node ( struct device_node * from ,
const struct of_device_id * matches )
{
struct device_node * np ;
read_lock ( & devtree_lock ) ;
np = from ? from - > allnext : allnodes ;
for ( ; np ; np = np - > allnext ) {
if ( of_match_node ( matches , np ) & & of_node_get ( np ) )
break ;
}
of_node_put ( from ) ;
read_unlock ( & devtree_lock ) ;
return np ;
}
EXPORT_SYMBOL ( of_find_matching_node ) ;